在Java正则表达式中使用.find()遍历字符串

在Java正则表达式中使用.find()遍历字符串,java,regex,string,Java,Regex,String,我目前正试图用正则表达式解决codingbat.com上的一个问题 我对这一点还不熟悉,所以请逐步解释。我可以用字符串方法相对容易地解决这个问题,但我正在尝试使用正则表达式 提示如下: 给定一个字符串和一个非空的单词字符串,返回一个由每个字符组成的字符串,该字符恰好位于字符串中单词的每个外观之前和之后。忽略单词前后没有字符的情况,如果字符位于两个单词之间,则可能包含两次字符 wordEnds("abcXY123XYijk", "XY") → "c13i" wordEnds("XY123XY",

我目前正试图用正则表达式解决codingbat.com上的一个问题

我对这一点还不熟悉,所以请逐步解释。我可以用字符串方法相对容易地解决这个问题,但我正在尝试使用正则表达式

提示如下: 给定一个字符串和一个非空的单词字符串,返回一个由每个字符组成的字符串,该字符恰好位于字符串中单词的每个外观之前和之后。忽略单词前后没有字符的情况,如果字符位于两个单词之间,则可能包含两次字符

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;
问题是,当一行中有多个word实例时,程序会丢失该单词前面的字符,因为m.find()的进程超出了该字符

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


我希望能提供一个不混乱的解决方案,并提供一个可以应用于其他一般正则表达式问题的解释。

使用正向前瞻和正向前瞻,这是零宽度断言

(?<=(.)|^)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
works使用正则表达式如下:

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

检查

这是一种单线性解决方案:

String wordEnds = input.replaceAll(".*?(.)" + word + "(?:(?=(.)" + word + ")|(.).*?(?=$|." + word + "))", "$1$2$3");
这与您的edge案例相匹配,作为非捕获组中的前瞻性案例,然后与常规(消费)案例相匹配

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

另外请注意,为了绝对安全,您应该转义
word
中的所有字符,以防其中任何字符是特殊的“regex”字符,因此如果您不能保证这一点,则需要使用
模式。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

查看这个关于look around regular expressions@user1796994的答案查看我的未删除、已修复的答案solution@user1796994请参阅我的(编辑的)答案,了解如何在一行中完成(包括测试代码)。你可能不认为它是“非杂乱”的,但它肯定没有多行解决方案那么混乱。这不太正确-我将回到这里later@Bohemian这是不正确的,他需要
cxziij
作为输出,而不是
cxzi
。这就是我使用lookarounds..。@Fake.It.Til.U.Make.It的原因,尽管我之前说过这不是一个解决方案,我已经找出了实际(真正)起作用的正则表达式-请参阅编辑后的答案,以获得完全起作用的单行解决方案。-1 WAAAAAAAAAY太复杂了,实际上是错误的。你不需要到处看看!只需使用
()
——他说“如果没有字符,则不匹配”,但你通过匹配开始和结束就完成了,这实际上不是OP所说的wants@Bohemian我喜欢你原来的答案,因为它很简单,所以如果你能发布它(用str.replace),我将不胜感激@波希米亚人你能说出哪怕一个例子这个正则表达式会在哪里吗fail@Fake.It.Til.U.Make.It我已经采取了我的平淡,现在感觉好多了-我已经删除了我的-1。这有点苛刻。我的批评是,这太复杂了。@Bohemian,怎么太复杂了?像“aaaX”这样的案例需要匹配开始和结束,像“axa”这样的案例需要环顾四周。移除它们将停止边缘案例的正确处理。
c13i
cxziij