// getRangeEnd(last) == MAX_VALUE)
// Invariant: list[len-1] == HIGH == MAX_VALUE + 1
// If limit == len then len is even and the last range ends with MAX_VALUE.
- if (len >= 4 && list[0] == 0 && limit == len) {
+ //
+ // *But* do not write the inverse (complement) if there are strings.
+ // Since ICU 70, the '^' performs a code point complement which removes all strings.
+ if (len >= 4 && list[0] == 0 && limit == len && !hasStrings()) {
// Emit the inverse
result.append(u'^');
// Offsetting the inversion list index by one lets us
uset_removeString(set, STR_ab, STR_ab_LEN);
expect(set, "acd{bc}", "bfg{ab}", NULL);
- /* [^acd{bc}] */
+ /* [[^acd]{bc}] */
uset_complement(set);
expect(set, "bef{bc}", "acd{ac}", NULL);
strlen(items)==0 ? "TRUE" : "FALSE");
}
- /* Don't test patterns starting with "[^" */
- if (u_strlen(ustr) > 2 && ustr[1] == 0x5e /*'^'*/) {
+ /* Don't test patterns starting with "[^" or "[\\u0000". */
+ if ((u_strlen(ustr) > 2 && ustr[1] == u'^') || uset_contains(set, 0)) {
return;
}
notBasic.contains(U'🚲'));
}
+ // When there are strings, we must not use the complement for a more compact toPattern().
+ {
+ UnicodeSet set;
+ set.add(0, u'Y').add(u'b', u'q').add(u'x', 0x10ffff);
+ UnicodeString pattern;
+ set.toPattern(pattern, true);
+ UnicodeSet set2(pattern, errorCode);
+ checkEqual(set, set2, "set(with 0 & max, only code points) pattern round-trip");
+ assertEquals("set(with 0 & max, only code points).toPattern()", u"[^Z-ar-w]", pattern);
+
+ set.add("ch").add("ss");
+ set.toPattern(pattern, true);
+ set2 = UnicodeSet(pattern, errorCode);
+ checkEqual(set, set2, "set(with 0 & max, with strings) pattern round-trip");
+ assertEquals("set(with 0 & max, with strings).toPattern()",
+ u"[\\u0000-Yb-qx-\\U0010FFFF{ch}{ss}]", pattern);
+ }
+
// The complement() API behavior does not change under this ticket.
{
UnicodeSet notBasic(u"[:Basic_Emoji:]", errorCode);
// getRangeEnd(last) == MAX_VALUE)
// Invariant: list[len-1] == HIGH == MAX_VALUE + 1
// If limit == len then len is even and the last range ends with MAX_VALUE.
- if (len >= 4 && list[0] == 0 && limit == len) {
+ //
+ // *But* do not write the inverse (complement) if there are strings.
+ // Since ICU 70, the '^' performs a code point complement which removes all strings.
+ if (len >= 4 && list[0] == 0 && limit == len && !hasStrings()) {
// Emit the inverse
result.append('^');
// Offsetting the inversion list index by one lets us
notBasic.contains("🚲"));
}
+ // When there are strings, we must not use the complement for a more compact toPattern().
+ {
+ UnicodeSet set = new UnicodeSet();
+ set.add(0, 'Y').add('b', 'q').add('x', 0x10ffff);
+ String pattern = set.toPattern(true);
+ UnicodeSet set2 = new UnicodeSet(pattern);
+ checkEqual(set, set2, "set(with 0 & max, only code points) pattern round-trip");
+ assertEquals("set(with 0 & max, only code points).toPattern()", "[^Z-ar-w]", pattern);
+
+ set.add("ch").add("ss");
+ pattern = set.toPattern(true);
+ set2 = new UnicodeSet(pattern);
+ checkEqual(set, set2, "set(with 0 & max, with strings) pattern round-trip");
+ assertEquals("set(with 0 & max, with strings).toPattern()",
+ "[\\u0000-Yb-qx-\\U0010FFFF{ch}{ss}]", pattern);
+ }
+
// The complement() API behavior does not change under this ticket.
{
UnicodeSet notBasic = new UnicodeSet("[:Basic_Emoji:]").complement();