5

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

我对此并不陌生,因此将不胜感激。我可以使用 String 方法相对容易地解决这个问题,但我正在尝试使用正则表达式。

提示如下:给定一个字符串和一个非空单词字符串,返回一个由字符串中每个单词出现之前和之后的每个字符组成的字符串。忽略单词前后没有字符的情况,如果字符在两个单词之间,它可能会被包含两次。

wordEnds("abcXY123XYijk", "XY") → "c13i"
wordEnds("XY123XY", "XY") → "13"
wordEnds("XY1XY", "XY") → "11"

ETC

到目前为止我的代码:

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;

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

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

我将不胜感激一个简单的解决方案,并附上我可以应用于其他一般正则表达式问题的解释。

4

3 回答 3

1

这是一个单行解决方案:

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

这将您的边缘情况匹配为非捕获组中的前瞻,然后匹配通常的(消费)情况。

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

另请注意,为了绝对安全,您应该转义所有字符,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"));
}

输出:

c13i
cxziij
于 2012-11-03T19:38:57.423 回答
0

使用零宽度断言的正向后视和正向前瞻

(?<=(.)|^)1(?=(.)|$)
    ^     ^     ^-looks for a character after 1 and captures it in group2
    |     |->matches 1..you can replace it with any word
    |
    |->looks for a character just before 1 and captures it in group 1..this is zero width assertion that doesn't move forward to match.it is just a test and thus allow us to capture the values

$1$2包含您的价值..继续寻找直到最后

所以这应该是

String s1 = "abcXY123XYiXYjk";
String s2 = java.util.regex.Pattern.quote("XY");
String s3 = "";
String r = "(?<=(.)|^)"+s2+"(?=(.)|$)";
Pattern p = Pattern.compile(r);
Matcher m = p.matcher(s1);
while(m.find()) s3 += m.group(1)+m.group(2);
//s3 now contains c13iij

这里工作

于 2012-11-03T19:19:40.847 回答
0

使用正则表达式如下:

Matcher m = Pattern.compile("(.|)" + Pattern.quote(b) + "(?=(.?))").matcher(a);
for (int i = 1; m.find(); c += m.group(1) + m.group(2), i++);

检查这个演示

于 2012-11-03T19:32:40.857 回答