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

时间:2012-11-03 19:10:15

标签: java regex string

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

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

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

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

到目前为止我的代码:

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"

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

3 个答案:

答案 0 :(得分:1)

这是一个单线解决方案:

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

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

请注意,您的要求不需要迭代,只有您的问题标题认为是必要的,而不是。

另请注意,为了绝对安全,您应该转义word中的所有字符,以防其中任何字符是特殊的“正则表达式”字符,因此如果您无法保证,则需要使用{{1而不是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"));
}

答案 1 :(得分: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

工作here

答案 2 :(得分:0)

使用正则表达式如下:

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

检查 this demo