Skip to content

Commit ace091b

Browse files
fix #1195 strcmp({'a'},[a]) did not return expected value (#1196)
1 parent 7b7be64 commit ace091b

File tree

3 files changed

+209
-121
lines changed

3 files changed

+209
-121
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3939
- help files generated sorted by name on all platforms.
4040
- on windows, Qt libraries used are in debug mode.
4141

42+
### Fixed
43+
44+
- [#1195](http://github.com/nelson-lang/nelson/issues/1195) `strcmp({'a'},["a"])` did not return expected value.
45+
4246
## 1.4.0 (2024-04-27)
4347

4448
### Added

modules/string/src/cpp/StringCompare.cpp

+169-116
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ compareString(const std::wstring& A, const std::wstring& B, bool bCaseSensitive,
4141
} else {
4242
bEq = StringHelpers::iequals(A, B);
4343
}
44-
4544
return bEq;
4645
}
4746
//=============================================================================
@@ -70,143 +69,197 @@ CompareStringString(const ArrayOf& A, const ArrayOf& B, bool bCaseSensitive, ind
7069
return ArrayOf::logicalConstructor(bEq);
7170
}
7271
//=============================================================================
73-
ArrayOf
74-
StringCompare(const ArrayOf& A, const ArrayOf& B, bool bCaseSensitive, indexType len)
72+
static ArrayOf
73+
StringCompareSameTypes(const ArrayOf& A, const ArrayOf& B, bool bCaseSensitive, indexType len)
7574
{
76-
ArrayOf res;
77-
if (A.isCharacterArray() && B.isCharacterArray()) {
78-
return CompareStringString(A, B, bCaseSensitive, len);
79-
}
80-
if ((A.isCell() && A.isEmpty()) || (B.isCell() && B.isEmpty())
81-
|| (A.isStringArray() && A.isEmpty()) || (B.isStringArray() && B.isEmpty())) {
82-
return ArrayOf::emptyConstructor();
83-
}
84-
if ((A.isCell() && B.isCell()) || (A.isStringArray() && B.isStringArray())) {
85-
Dimensions dimA = A.getDimensions();
86-
Dimensions dimB = B.getDimensions();
87-
if (dimA.equals(dimB)) {
88-
size_t Clen = dimA.getElementCount();
89-
logical* Cp = static_cast<logical*>(
90-
ArrayOf::allocateArrayOf(NLS_LOGICAL, Clen, stringVector(), true));
91-
auto* cellA = (ArrayOf*)(A.getDataPointer());
92-
auto* cellB = (ArrayOf*)(B.getDataPointer());
93-
for (size_t k = 0; k < Clen; k++) {
94-
ArrayOf elementA = cellA[k];
95-
ArrayOf elementB = cellB[k];
96-
if (elementA.isRowVectorCharacterArray() && elementB.isRowVectorCharacterArray()) {
97-
Cp[k] = static_cast<Nelson::logical>(
98-
compareString(elementA.getContentAsWideString(),
99-
elementB.getContentAsWideString(), bCaseSensitive, len));
100-
} else if (elementA.isCharacterArray() && elementB.isCharacterArray()) {
101-
wstringVector s1 = elementA.getContentAsWideStringVector();
102-
wstringVector s2 = elementB.getContentAsWideStringVector();
103-
if (s1.size() == s2.size()) {
104-
Cp[k] = true;
105-
}
106-
} else {
107-
Cp[k] = false;
75+
Dimensions dimA = A.getDimensions();
76+
Dimensions dimB = B.getDimensions();
77+
if (dimA.equals(dimB)) {
78+
size_t Clen = dimA.getElementCount();
79+
logical* Cp = static_cast<logical*>(
80+
ArrayOf::allocateArrayOf(NLS_LOGICAL, Clen, stringVector(), true));
81+
auto* cellA = (ArrayOf*)(A.getDataPointer());
82+
auto* cellB = (ArrayOf*)(B.getDataPointer());
83+
for (size_t k = 0; k < Clen; k++) {
84+
ArrayOf elementA = cellA[k];
85+
ArrayOf elementB = cellB[k];
86+
if (elementA.isRowVectorCharacterArray() && elementB.isRowVectorCharacterArray()) {
87+
Cp[k]
88+
= static_cast<Nelson::logical>(compareString(elementA.getContentAsWideString(),
89+
elementB.getContentAsWideString(), bCaseSensitive, len));
90+
} else if (elementA.isCharacterArray() && elementB.isCharacterArray()) {
91+
wstringVector s1 = elementA.getContentAsWideStringVector();
92+
wstringVector s2 = elementB.getContentAsWideStringVector();
93+
if (s1.size() == s2.size()) {
94+
Cp[k] = true;
10895
}
96+
} else {
97+
Cp[k] = false;
10998
}
110-
res = ArrayOf(NLS_LOGICAL, dimA, Cp);
111-
} else {
112-
if (dimA.isScalar() || dimB.isScalar()) {
113-
size_t Clen = 0;
114-
Dimensions dimC;
99+
}
100+
return ArrayOf(NLS_LOGICAL, dimA, Cp);
101+
} else {
102+
if (dimA.isScalar() || dimB.isScalar()) {
103+
size_t Clen = 0;
104+
Dimensions dimC;
105+
if (dimA.isScalar()) {
106+
Clen = dimB.getElementCount();
107+
dimC = dimB;
108+
} else {
109+
Clen = dimA.getElementCount();
110+
dimC = dimA;
111+
}
112+
logical* Cp = static_cast<logical*>(
113+
ArrayOf::allocateArrayOf(NLS_LOGICAL, Clen, stringVector(), true));
114+
auto* cellA = (ArrayOf*)A.getDataPointer();
115+
auto* cellB = (ArrayOf*)B.getDataPointer();
116+
for (size_t k = 0; k < Clen; ++k) {
117+
ArrayOf p1;
118+
ArrayOf p2;
115119
if (dimA.isScalar()) {
116-
Clen = dimB.getElementCount();
117-
dimC = dimB;
120+
p1 = cellA[0];
121+
p2 = cellB[k];
118122
} else {
119-
Clen = dimA.getElementCount();
120-
dimC = dimA;
123+
p1 = cellA[k];
124+
p2 = cellB[0];
121125
}
122-
logical* Cp = static_cast<logical*>(
123-
ArrayOf::allocateArrayOf(NLS_LOGICAL, Clen, stringVector(), true));
124-
auto* cellA = (ArrayOf*)A.getDataPointer();
125-
auto* cellB = (ArrayOf*)B.getDataPointer();
126-
for (size_t k = 0; k < Clen; ++k) {
127-
ArrayOf p1;
128-
ArrayOf p2;
129-
if (dimA.isScalar()) {
130-
p1 = cellA[0];
131-
p2 = cellB[k];
132-
} else {
133-
p1 = cellA[k];
134-
p2 = cellB[0];
135-
}
136-
if (p1.isCharacterArray() && p2.isCharacterArray()) {
137-
wstringVector s1 = p1.getContentAsWideStringVector();
138-
wstringVector s2 = p2.getContentAsWideStringVector();
139-
if (s1.size() == s2.size()) {
140-
Cp[k] = true;
141-
for (size_t l = 0; l < s1.size(); ++l) {
142-
if (s1[l] != s2[l]) {
143-
Cp[k] = false;
144-
break;
145-
}
126+
if (p1.isCharacterArray() && p2.isCharacterArray()) {
127+
wstringVector s1 = p1.getContentAsWideStringVector();
128+
wstringVector s2 = p2.getContentAsWideStringVector();
129+
if (s1.size() == s2.size()) {
130+
Cp[k] = true;
131+
for (size_t l = 0; l < s1.size(); ++l) {
132+
if (s1[l] != s2[l]) {
133+
Cp[k] = false;
134+
break;
146135
}
147136
}
148137
}
149138
}
150-
res = ArrayOf(NLS_LOGICAL, dimC, Cp);
151-
} else {
152-
Error(ERROR_SAME_SIZE_EXPECTED);
153139
}
154-
}
155-
} else if (A.isCell() || B.isCell() || A.isStringArray() || B.isStringArray()) {
156-
Dimensions dimsA = A.getDimensions();
157-
Dimensions dimsB = B.getDimensions();
158-
159-
bool checkDims = false;
160-
if ((!A.isCell() && !A.isStringArray()) || (!B.isCell() && !B.isStringArray())) {
161-
checkDims = true;
140+
return ArrayOf(NLS_LOGICAL, dimC, Cp);
162141
} else {
163-
checkDims = A.isRowVectorCharacterArray() || B.isRowVectorCharacterArray()
164-
|| (A.isStringArray() && A.isScalar()) || (B.isStringArray() && B.isScalar())
165-
|| (A.isCell() && A.isScalar()) || (B.isCell() && B.isScalar())
166-
|| dimsA.equals(dimsB);
167-
}
168-
if (!checkDims) {
169-
Error(_W("Same size or scalar expected."));
142+
Error(_W("Inputs must be the same size or either one can be a scalar."),
143+
L"Nelson:strcmp:InputsSizeMismatch");
170144
}
171-
size_t Clen;
172-
Dimensions dimC;
173-
ArrayOf cell1;
174-
ArrayOf scalar2;
175-
if (A.isCell() || A.isStringArray()) {
176-
cell1 = A;
177-
scalar2 = B;
178-
dimC = A.getDimensions();
179-
Clen = dimC.getElementCount();
145+
}
146+
return {};
147+
}
148+
//=============================================================================
149+
static ArrayOf
150+
StringCompareMixedTypes(const ArrayOf& A, const ArrayOf& B, bool bCaseSensitive, indexType len)
151+
{
152+
Dimensions dimsA = A.getDimensions();
153+
Dimensions dimsB = B.getDimensions();
154+
if ((A.isCell() && A.isScalar() && B.isScalarStringArray())
155+
|| (B.isCell() && B.isScalar() && A.isScalarStringArray())) {
156+
std::wstring scalarStr;
157+
ArrayOf* elements;
158+
Dimensions dims;
159+
if (A.isScalarStringArray()) {
160+
scalarStr = A.getContentAsWideString();
161+
elements = (ArrayOf*)B.getDataPointer();
162+
dims = B.getDimensions();
180163
} else {
181-
cell1 = B;
182-
scalar2 = A;
183-
dimC = B.getDimensions();
184-
Clen = dimC.getElementCount();
164+
scalarStr = B.getContentAsWideString();
165+
elements = (ArrayOf*)A.getDataPointer();
166+
dims = A.getDimensions();
185167
}
168+
std::wstring cellScalarStr = elements[0].getContentAsWideString();
169+
return ArrayOf::logicalConstructor(compareString(scalarStr, cellScalarStr, bCaseSensitive));
170+
}
186171

187-
logical* Cp = static_cast<logical*>(
188-
ArrayOf::allocateArrayOf(NLS_LOGICAL, Clen, stringVector(), true));
189-
auto* cellA = (ArrayOf*)(cell1.getDataPointer());
190-
for (size_t k = 0; k < Clen; k++) {
191-
if (!scalar2.isCharacterArray()) {
192-
Cp[k] = false;
172+
bool checkDims = false;
173+
if ((!A.isCell() && !A.isStringArray()) || (!B.isCell() && !B.isStringArray())) {
174+
checkDims = true;
175+
} else {
176+
checkDims = A.isRowVectorCharacterArray() || B.isRowVectorCharacterArray()
177+
|| (A.isStringArray() && A.isScalar()) || (B.isStringArray() && B.isScalar())
178+
|| (A.isCell() && A.isScalar()) || (B.isCell() && B.isScalar()) || dimsA.equals(dimsB);
179+
}
180+
if (!checkDims) {
181+
Error(_W("Inputs must be the same size or either one can be a scalar."),
182+
L"Nelson:strcmp:InputsSizeMismatch");
183+
}
184+
size_t Clen;
185+
Dimensions dimC;
186+
ArrayOf cell1;
187+
ArrayOf scalar2;
188+
if (A.isCell() || A.isStringArray()) {
189+
cell1 = A;
190+
scalar2 = B;
191+
dimC = A.getDimensions();
192+
Clen = dimC.getElementCount();
193+
} else {
194+
cell1 = B;
195+
scalar2 = A;
196+
dimC = B.getDimensions();
197+
Clen = dimC.getElementCount();
198+
}
199+
200+
logical* Cp
201+
= static_cast<logical*>(ArrayOf::allocateArrayOf(NLS_LOGICAL, Clen, stringVector(), true));
202+
auto* cellA = (ArrayOf*)(cell1.getDataPointer());
203+
for (size_t k = 0; k < Clen; k++) {
204+
if (!scalar2.isCharacterArray() && !scalar2.isScalarStringArray()) {
205+
Cp[k] = false;
206+
} else {
207+
ArrayOf elementA = cellA[k];
208+
if ((elementA.isCharacterArray()) && (scalar2.isCharacterArray())) {
209+
Cp[k]
210+
= static_cast<Nelson::logical>(compareString(elementA.getContentAsWideString(),
211+
scalar2.getContentAsWideString(), bCaseSensitive, len));
193212
} else {
194-
ArrayOf elementA = cellA[k];
195-
if (elementA.isCharacterArray() && scalar2.isCharacterArray()) {
196-
Cp[k] = static_cast<Nelson::logical>(
197-
compareString(elementA.getContentAsWideString(),
198-
scalar2.getContentAsWideString(), bCaseSensitive, len));
199-
} else {
200-
Cp[k] = false;
201-
}
213+
Cp[k] = false;
202214
}
203215
}
204-
res = ArrayOf(NLS_LOGICAL, dimC, Cp);
216+
}
217+
return ArrayOf(NLS_LOGICAL, dimC, Cp);
218+
}
219+
//=============================================================================
220+
static ArrayOf
221+
StringCompareEmpty(const ArrayOf& A, const ArrayOf& B, bool bCaseSensitive, indexType len)
222+
{
223+
Dimensions dimA = A.getDimensions();
224+
Dimensions dimB = B.getDimensions();
225+
226+
Dimensions dim;
227+
if (dimA.equals(dimB)) {
228+
dim = dimA;
229+
} else if (dimA.isSquare()) {
230+
dim = dimB;
231+
} else if (dimB.isSquare()) {
232+
dim = dimA;
205233
} else {
206-
res = ArrayOf::logicalConstructor(false);
234+
Error(_W("Inputs must be the same size or either one can be a scalar."),
235+
L"Nelson:strcmp:InputsSizeMismatch");
207236
}
208237

209-
return res;
238+
charType* Cp
239+
= static_cast<charType*>(ArrayOf::allocateArrayOf(NLS_LOGICAL, 0, stringVector(), true));
240+
return ArrayOf(NLS_LOGICAL, dim, Cp);
241+
}
242+
//=============================================================================
243+
ArrayOf
244+
StringCompare(const ArrayOf& A, const ArrayOf& B, bool bCaseSensitive, indexType len)
245+
{
246+
if (A.isEmpty() && B.isEmpty() && (!A.isCharacterArray() && !B.isCharacterArray())) {
247+
return StringCompareEmpty(A, B, bCaseSensitive, len);
248+
}
249+
if (A.isCharacterArray() && B.isCharacterArray()) {
250+
return CompareStringString(A, B, bCaseSensitive, len);
251+
}
252+
if ((A.isCell() && A.isEmpty()) || (B.isCell() && B.isEmpty())
253+
|| (A.isStringArray() && A.isEmpty()) || (B.isStringArray() && B.isEmpty())) {
254+
return ArrayOf::emptyConstructor();
255+
}
256+
if ((A.isCell() && B.isCell()) || (A.isStringArray() && B.isStringArray())) {
257+
return StringCompareSameTypes(A, B, bCaseSensitive, len);
258+
}
259+
if (A.isCell() || B.isCell() || A.isStringArray() || B.isStringArray()) {
260+
return StringCompareMixedTypes(A, B, bCaseSensitive, len);
261+
}
262+
return ArrayOf::logicalConstructor(false);
210263
}
211264
//=============================================================================
212265
} // namespace Nelson

modules/string/tests/test_strcmp.m

+36-5
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828
assert_isequal(res, ref);
2929
%=============================================================================
3030
res = strcmp({}, []);
31-
ref = [];
31+
ref = logical([]);
3232
assert_isequal(res, ref);
3333
%=============================================================================
3434
res = strcmp({}, {});
35-
ref = [];
35+
ref = logical([]);
3636
assert_isequal(res, ref);
3737
%=============================================================================
3838
res = strcmp('', 'test');
@@ -162,7 +162,7 @@
162162
assert_isequal(res, ref);
163163
%=============================================================================
164164
cmd = 'res = strcmp(["a", "b", "c", "d"], ["a"; "b"; "c"; "d"]);';
165-
assert_checkerror(cmd, _('Same size expected.'));
165+
assert_checkerror(cmd, _('Inputs must be the same size or either one can be a scalar.'));
166166
%=============================================================================
167167
A = ["abc", "def"; NaN, "def"];
168168
B = 'def';
@@ -172,5 +172,36 @@
172172
%=============================================================================
173173
A = ["abc", "def"; NaN, "def"];
174174
B = {'abc'; 'def'};
175-
assert_checkerror('res = strcmp(A, B)', _('Same size or scalar expected.'));
176-
%=============================================================================
175+
assert_checkerror('res = strcmp(A, B)', _('Inputs must be the same size or either one can be a scalar.'));
176+
%=============================================================================
177+
c1 = 'time';
178+
c2 = {"Once","upon"; "a","time"};
179+
res = strcmp(c1, c2);
180+
REF = [false, false; false, false];
181+
assert_isequal(res, REF);
182+
%=============================================================================
183+
c1 = 'time';
184+
c2 = ["Once","upon"; "a","time"];
185+
res = strcmp(c1, c2);
186+
REF = [false, false; false, true];
187+
assert_isequal(res, REF);
188+
%=============================================================================
189+
c1 = ["time";"upon"];
190+
c2 = ["Once","upon"; "a","time"];
191+
assert_checkerror('res = strcmp(c1, c2)', _('Inputs must be the same size or either one can be a scalar.'));
192+
%=============================================================================
193+
c1 = {'time'};
194+
c2 = "time";
195+
res = strcmp(c1, c2);
196+
assert_istrue(res);
197+
%=============================================================================
198+
c1 = {'time'};
199+
c2 = 'time';
200+
res = strcmp(c1, c2);
201+
assert_istrue(res);
202+
%=============================================================================
203+
R = strcmp({'a'},["a"]);
204+
assert_istrue(R);
205+
%=============================================================================
206+
207+

0 commit comments

Comments
 (0)