2

我有以下字符串:

String str = "Klaße, STRAßE, FUß";

使用组合正则表达式我想将德语ß字母分别替换为ssSS。要执行此操作,我有:

String replaceUml = str
        .replaceAll("ß", "ss")
        .replaceAll("A-Z|ss$", "SS")
        .replaceAll("^(?=^A-Z)(?=.*A-Z$)(?=.*ss).*$", "SS");

预期结果:

Klasse, STRASSE, FUSS

实际结果:

Klasse, STRAssE, FUSS

我哪里错了?

4

4 回答 4

4

首先,如果你想匹配 AZ 范围内的某个字符,你需要把它放在方括号中。这个

.replaceAll("A-Z|ss$", "SS")

将在源代码中查找三个字符 AZ,这不是您想要的。其次,我认为你对什么感到困惑 | 方法。如果你这样说:

.replaceAll("[A-Z]|ss$", "SS")

它将用 SS 替换单词末尾的任何大写字母,因为 | 意思是寻找这个那个。

您的方法的第三个问题是,第二个和第三个 replaceAll 将查找原始字符串中的任何 ss,即使它不是来自 ß。这可能是也可能不是您想要的。

这是我要做的:

String replaceUml = str
    .replaceAll("(?<=[A-Z])ß", "SS")
    .replaceAll("ß", "ss");

如果 ß 之前的字符是大写字母,这将首先用 SS 替换所有 ß;然后如果有剩余的 ß,它们将被 ss 替换。实际上,如果 ß 之前的字符是 Ä 之类的变音符号,这将不起作用,因此您可能应该将其更改为

String replaceUml = str
    .replaceAll("(?<=[A-ZÄÖÜ])ß", "SS")
    .replaceAll("ß", "ss");

(可能有更好的方法来指定“大写 Unicode 字母”;我会寻找它。)

编辑:

String replaceUml = str
    .replaceAll("(?<=\\p{Lu})ß", "SS")
    .replaceAll("ß", "ss");

一个问题是,如果 ß 是文本中的第二个字符,并且单词的第一个字母是大写的,但单词的其余部分不是,则它不起作用。在这种情况下,您可能需要小写的“ss”。

String replaceUml = str
    .replaceAll("(?<=\\b\\p{Lu})ß(?=\\P{Lu})", "ss")
    .replaceAll("(?<=\\p{Lu})ß", "SS")
    .replaceAll("ß", "ss");

现在第一个将 ß 替换为 ss 如果它前面有一个大写字母,该字母是单词的第一个字母,但后面有一个不是大写字母的字符。 \P{Lu}带有大写字母 P 将匹配除大写字母以外的任何字符(它是\p{Lu}带有小写字母 p 的负数)。我还包括 \b 来测试单词的第一个字符。

于 2013-08-20T15:40:51.687 回答
2
String replaceUml = str
    .replaceAll("(?<=\\p{Lu})ß", "SS")
    .replace("ß", "ss")

这使用带有前面的 unicode 大写字母(“SÜß”)的正则表达式,具有大写“SS”

(?<= ... )是一种look-behind,一种上下文匹配。你也可以做

    .replaceAll("(\\p{Lu})ß", "$1SS")

因为ß一开始不会发生。

您的主要问题是没有使用括号[A-Z]

于 2013-08-20T15:38:41.587 回答
0

将您的正则表达式分成几部分:

正则表达式 101 演示

正则表达式

/ß/g

描述

ß Literal ß
g modifier: global. All matches (don't return on first match)

可视化

正则表达式可视化


正则表达式 101 演示

正则表达式

/([A-Z])ss$/g

描述

1st Capturing group ([A-Z]) 
    Char class [A-Z]  matches:
        A-Z A character range between Literal A and Literal Z
ss Literal ss
$ End of string
g modifier: global. All matches (don't return on first match)

可视化

正则表达式可视化


正则表达式 101 演示

正则表达式

/([A-Z]+)ss([A-Z]+)/g

描述

1st Capturing group ([A-Z]+) 
    Char class [A-Z] 1 to infinite times [greedy] matches:
        A-Z A character range between Literal A and Literal Z
ss Literal ss
2nd Capturing group ([A-Z]+) 
    Char class [A-Z] 1 to infinite times [greedy] matches:
        A-Z A character range between Literal A and Literal Z
g modifier: global. All matches (don't return on first match)

可视化

正则表达式可视化


专门为你

String replaceUml = str
    .replaceAll("ß", "ss")
    .replaceAll("([A-Z])ss$", "$1SS")
    .replaceAll("([A-Z]+)ss([A-Z]+)", "$1SS$2");
于 2013-08-20T15:38:13.320 回答
-1

使用String.replaceFirst()而不是 String.replaceAll()。

replaceAll("ß", "ss")

这将替换所有出现的“ß”。因此,此语句之后的输出变为如下所示:

克拉斯、STRAssE、FUss

现在replaceAll("A-Z|ss$", "SS")用“SS”替换最后出现的“ss”,因此您的最终结果如下所示:

克拉斯、斯特拉斯、大惊小怪

要获得您的预期结果,请尝试以下操作:

String replaceUml = str.replaceFirst("ß", "ss").replaceAll("ß", "SS");
于 2013-08-20T15:29:41.477 回答