不需要为此使用正则表达式,当然也不应该使用split("\\s+"),因为您会丢失连续的空格,并且空白字符的类型(即结果的空格)可能不正确。
您也不应该使用 charAt() 或类似的东西,因为它不支持来自 Unicode 补充平面的字母,即作为代理对存储在 Java 字符串中的 Unicode 字符。
基本逻辑:
- 找到单词的开头,即字符串的开头或空格后面的第一个字符。
- 找到单词的结尾,即空格或字符串结尾之前的最后一个字符。
- 从头到尾并行迭代:
作为 Java 代码,具有完整的 Unicode 支持:
public static String reverseLettersOfWords(String input) {
int[] codePoints = input.codePoints().toArray();
for (int i = 0, start = 0; i <= codePoints.length; i++) {
if (i == codePoints.length || Character.isWhitespace(codePoints[i])) {
for (int end = i - 1; ; start++, end--) {
while (start < end && ! Character.isLetter(codePoints[start]))
start++;
while (start < end && ! Character.isLetter(codePoints[end]))
end--;
if (start >= end)
break;
int tmp = codePoints[start];
codePoints[start] = codePoints[end];
codePoints[end] = tmp;
}
start = i + 1;
}
}
return new String(codePoints, 0, codePoints.length);
}
测试
System.out.println(reverseLettersOfWords("Hello"));
System.out.println(reverseLettersOfWords("Hello!"));
System.out.println(reverseLettersOfWords("I'm saying Hello!"));
System.out.println(reverseLettersOfWords("I haven't said hello yet, but I will."));
System.out.println(reverseLettersOfWords("Works with surrogate pairs: ???+? "));
输出
olleH
olleH!
m'I gniyas olleH!
I tneva'h dias olleh tey, tub I lliw.
skroW htiw etagorrus sriap: ???+?
请注意,末尾的特殊字母是“脚本(或书法)”、“粗体”列中显示的前 4 个 here,例如? 是 Unicode Character 'MATHEMATICAL BOLD SCRIPT CAPITAL A' (U+1D4D0),在 Java 中是两个字符 "\uD835\uDCD0"。
更新
上面的实现是为反转单词的字母而优化的。要应用任意操作来破坏单词的字母,请使用以下实现:
public static String mangleLettersOfWords(String input) {
int[] codePoints = input.codePoints().toArray();
for (int i = 0, start = 0; i <= codePoints.length; i++) {
if (i == codePoints.length || Character.isWhitespace(codePoints[i])) {
int wordCodePointLen = 0;
for (int j = start; j < i; j++)
if (Character.isLetter(codePoints[j]))
wordCodePointLen++;
if (wordCodePointLen != 0) {
int[] wordCodePoints = new int[wordCodePointLen];
for (int j = start, k = 0; j < i; j++)
if (Character.isLetter(codePoints[j]))
wordCodePoints[k++] = codePoints[j];
int[] mangledCodePoints = mangleWord(wordCodePoints.clone());
if (mangledCodePoints.length != wordCodePointLen)
throw new IllegalStateException("Mangled word is wrong length: '" + new String(wordCodePoints, 0, wordCodePoints.length) + "' (" + wordCodePointLen + " code points)" +
" vs mangled '" + new String(mangledCodePoints, 0, mangledCodePoints.length) + "' (" + mangledCodePoints.length + " code points)");
for (int j = start, k = 0; j < i; j++)
if (Character.isLetter(codePoints[j]))
codePoints[j] = mangledCodePoints[k++];
}
start = i + 1;
}
}
return new String(codePoints, 0, codePoints.length);
}
private static int[] mangleWord(int[] codePoints) {
return mangleWord(new String(codePoints, 0, codePoints.length)).codePoints().toArray();
}
private static CharSequence mangleWord(String word) {
return new StringBuilder(word).reverse();
}
如果需要,您当然可以将对 mangleWord 方法的硬编码调用替换为对传入的 Function<int[], int[]> 或 Function<String, ? extends CharSequence> 参数的调用。
mangleWord 方法实现的结果与原始实现相同,但您现在可以轻松实现不同的修饰算法。
例如要随机化字母,只需 shuffle codePoints 数组:
private static int[] mangleWord(int[] codePoints) {
Random rnd = new Random();
for (int i = codePoints.length - 1; i > 0; i--) {
int j = rnd.nextInt(i + 1);
int tmp = codePoints[j];
codePoints[j] = codePoints[i];
codePoints[i] = tmp;
}
return codePoints;
}
样本输出
Hlelo
Hlleo!
m'I nsayig oHlel!
I athen'v siad eohll yte, btu I illw.
srWok twih rueoatrsg rpasi: ???+?