例如,以下面的String
列表为例,忽略反逗号:
"Hello"
"Hello!"
"I'm saying Hello!"
"I haven't said hello yet, but I will."
现在假设我想对每个单词的字符执行特定的操作-例如,假设我想颠倒字符,但保留标点符号的位置。因此,结果将是:
"olleH"
"olleH!"
"m'I gniyas olleH!"
"I tneva'h dias olleh tey, tub I lliw."
理想情况下,我希望我的代码是独立于对字符串执行的操作的(另一个例子是字母的随机洗牌),并且独立于所有标点符号-因此,在执行操作之后,所有连字符、撇号、逗号、句号、en/em破折号等都保留在它们的原始位置。这可能需要某种形式的正则表达式。
为此,我认为我应该保存给定单词中所有标点符号的索引和字符,执行操作,然后在正确的位置重新插入所有标点符号。然而,我想不出一种方法来做这件事,也想不出一个可以使用的类。
我进行了第一次尝试,但不幸的是,这不适用于标点符号,这是关键:
jshell> String str = "I haven't said hello yet, but I will."
str ==> "I haven't said hello yet, but I will."
jshell> Arrays.stream(str.split("\\s+")).map(x -> (new StringBuilder(x)).reverse().toString()).reduce((x, y) -> x + " " + y).get()
$2 ==> "I t'nevah dias olleh ,tey tub I .lliw"
有谁知道我该怎么解决这个问题吗?非常感谢。不需要完整的工作代码--也许只需要一个适当的类的路标,我就可以用来执行这个操作。
发布于 2019-04-15 11:42:38
不需要使用正则表达式,当然也不应该使用split("\\s+")
,因为您会丢失连续的空格和空格字符的类型,即结果的空格可能是不正确的。
您也不应该使用charAt()
或任何类似的东西,因为这不支持来自Unicode Supplemental平面的字母,即作为代理对存储在Java string中的Unicode字符。
基本逻辑:
查找单词的开始,即字符串的开始或单词结束后的第一个字符,即空格之前的最后一个字符或从开始和结束平行开始的string.
的
作为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”,例如the is 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
方法实现的结果与原始实现相同,但是您现在可以轻松地实现不同的破坏算法。
例如,要随机化字母,只需对codePoints
数组执行shuffle操作:
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: +
发布于 2019-04-15 11:29:00
我怀疑有一个更有效的解决方案,但这里有一个天真的解决方案:
将句子拆分成空格中的单词(注意-如果您有多个空格,我的实现将让problems)
public class Reverser {
public String reverseSentence(String sentence) {
String[] words = sentence.split(" ");
return Arrays.stream(words).map(this::reverseWord).collect(Collectors.joining(" "));
}
private String reverseWord(String word) {
String noPunctuation = word.replaceAll("\\W", "");
String reversed = new StringBuilder(noPunctuation).reverse().toString();
StringBuilder result = new StringBuilder();
for (int i = 0; i < word.length(); ++i) {
char ch = word.charAt(i);
if (!Character.isAlphabetic(ch) && !Character.isDigit(ch)) {
result.append(ch);
}
if (i < reversed.length()) {
result.append(reversed.charAt(i));
}
}
return result.toString();
}
}
https://stackoverflow.com/questions/55682123
复制相似问题