使用Java正则表达式中的.find()迭代String

Ris*_*shi 5 java regex string

我正在尝试使用正则表达式解决来自codingbat.com的问题.

我是新手,所以一步一步的解释将不胜感激.我可以相对容易地使用String方法解决这个问题,但我正在尝试使用正则表达式.

这是提示:给定一个字符串和一个非空字符串,在字符串中每次出现单词之前和之后返回由每个char组成的字符串.忽略在单词之前或之后没有字符的情况,如果字符位于两个单词之间,则可以包括两次char.

wordEnds("abcXY123XYijk", "XY") ? "c13i"
wordEnds("XY123XY", "XY") ? "13"
wordEnds("XY1XY", "XY") ? "11"
Run Code Online (Sandbox Code Playgroud)

等等

我的代码到目前为止:

String regex = ".?" + word+ ".?";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);

String newStr = "";
while(m.find())
    newStr += m.group().replace(word, "");

return newStr;
Run Code Online (Sandbox Code Playgroud)

问题是当一行中有多个单词实例时,程序会错过单词前面的字符,因为m.find()会超出它.

例如:wordEnds("abc1xyz1i1j", "1")应该返回"cxziij",但我的方法返回"cxzij",而不是重复"i"

我将非常感谢一个非混乱的解决方案,并且可以解释我可以应用于其他一般正则表达式问题.

Boh*_*ian 1

这是一个单行解决方案:

String wordEnds = input.replaceAll(".*?(.)" + word + "(?:(?=(.)" + word + ")|(.).*?(?=$|." + word + "))", "$1$2$3");
Run Code Online (Sandbox Code Playgroud)

这与您的边缘情况匹配,作为非捕获组内的前瞻,然后匹配通常(消耗)的情况。

请注意,您的要求不需要迭代,只有您的问题标题认为这是必要的,但事实并非如此。

另请注意,为了绝对安全,您应该转义所有字符,word以防其中任何字符是特殊的“正则表达式”字符,因此如果您不能保证这一点,则需要使用Pattern.quote(word)使用word.

这是对通常情况和边缘情况的测试,表明它是有效的:

public static String wordEnds(String input, String word) {
    word = Pattern.quote(word); // add this line to be 100% safe
    return input.replaceAll(".*?(.)" + word + "(?:(?=(.)" + word + ")|(.).*?(?=$|." + word + "))", "$1$2$3");
}

public static void main(String[] args) {
    System.out.println(wordEnds("abcXY123XYijk", "XY"));
    System.out.println(wordEnds("abc1xyz1i1j", "1"));
}
Run Code Online (Sandbox Code Playgroud)

输出:

c13i
cxziij
Run Code Online (Sandbox Code Playgroud)