Вы можете создать пользовательский компаратор, который оборачивает разборщик и обрабатывает вручную v
и w
так, как вы хотите.
Я сделал две реализации этого.
Первый из них короткий и элегантный, он использует компаратор Guavas lexicographical
вместе с хитрым регулярным выражением, которое Хольгер представил в комментарии.
private static final Pattern VW_BOUNDARY = Pattern.compile("(?=[vw])|(?<=[vw])", Pattern.CASE_INSENSITIVE);
public static Comparator<String> smallCorrectVwWrapper(Comparator<Object> original) {
return Comparator.comparing(
s -> Arrays.asList(VW_BOUNDARY.split((String) s)),
Comparators.lexicographical(original));
Вторая реализация - большая и сложная вещькоторый делает то же самое, но реализуется вручную, без библиотек и регулярных выражений.
public static Comparator<String> correctVwWrapper(Comparator<Object> original) {
return (s1, s2) -> compareSplittedVw(original, s1, s2);
}
/**
* Compares the two string by first splitting them into segments separated by W
* and V, then comparing the segments one by one.
*/
private static int compareSplittedVw(Comparator<Object> original, String s1, String s2) {
List<String> l1 = splitVw(s1);
List<String> l2 = splitVw(s2);
int minSize = Math.min(l1.size(), l2.size());
for (int ix = 0; ix < minSize; ix++) {
int comp = original.compare(l1.get(ix), l2.get(ix));
if (comp != 0) {
return comp;
}
}
return Integer.compare(l1.size(), l2.size());
}
private static boolean isVw(int ch) {
return ch == 'V' || ch == 'v' || ch == 'W' || ch == 'w';
}
/**
* Splits the string into segments separated by V and W.
*/
public static List<String> splitVw(String s) {
var b = new StringBuilder();
var result = new ArrayList<String>();
for (int offset = 0; offset < s.length();) {
int ch = s.codePointAt(offset);
if (isVw(ch)) {
if (b.length() > 0) {
result.add(b.toString());
b.setLength(0);
}
result.add(Character.toString((char) ch));
} else {
b.appendCodePoint(ch);
}
offset += Character.charCount(ch);
}
if (b.length() > 0) {
result.add(b.toString());
}
return result;
}
Использование:
public static void main(String[] args) throws Exception {
Comparator<String> stringComparator = correctVwWrapper(Collator.getInstance(new Locale("sv", "SE")));
System.out.println(stringComparator.compare("a", "z") < 0); // true
System.out.println(stringComparator.compare("wa", "vz") < 0); // false
System.out.println(stringComparator.compare("wwa", "vvz") < 0); // false
System.out.println(stringComparator.compare("va", "wz") < 0); // true
System.out.println(stringComparator.compare("v", "w") < 0); // true
}
Немного больше работы для реализации переноса Collator
, но это не должно быть слишком сложно.