java - 正则表达式中的负向前瞻匹配所有接受特定字符的内容

标签 java regex regex-lookarounds

我在 Java 中定义带有负向前瞻的正则表达式时遇到问题。

给定以下字符串:

今天[#[#item#] |元素#]已发货,所以[#it is|它们#]消失了。

我正在尝试根据某个值将此字符串转换为以下形式之一(是的,这是区分单数和复数形式的一种方法):

今天 [#item#] 已发货,因此已消失。今天商品已发货,因此已消失

我正在尝试使用 Java 中的正则表达式来匹配此模式并实现此转换:

public String convert(String text, boolean isSingular) {
    Pattern spPattern = Pattern.compile("\\[#.*?\\|.*?#\\]");
    Matcher matcher = spPattern.matcher(text);
    while (matcher.find()) {
        int start = matcher.start()+2;
        int end = matcher.end()-2;
        int indexOfPipe = text.indexOf("|", start);
        String replacement = (isSingular) ? text.substring(start, indexOfPipe) : text.substring(indexOfPipe+1, end);
        text = matcher.replaceFirst(replacement);
        matcher = spPattern.matcher(text);
     }
}

对于单数形式:在 while 第一次迭代之后,text今天 [#item#] 已发货,所以 [#it is|they are#] 消失了。,这是可以的。然而,在第二次迭代中,Matcher 与已发货的组 [#item#] 相匹配,因此 [#it is|they are#],而它应该是 [#it is|they are#]。我很确定我需要某种消极的前瞻。

我已经尝试过以下模式,但它似乎没有做任何事情:

(\\[#.*?\\|.*?#\\])(?!\\[#[^\\|]*?#\\])(“尝试匹配 [# 和 #] 之间的所有内容,接受那些标签之间不包含 | 的情况”)

我错过了什么?

最佳答案

简介

您遇到的问题是因为您的第一个替换正在生成今天 [#item#] 已发货,因此 [#it is|they are#] 消失了。 并且您的正则表达式匹配 [#item#] 已发货,因此 [#it is|they are#]。然后,您的正则表达式会错误地替换该字符串。

解决这个问题的真正方法是创建一个解析器,但是如果函数以递归方式运行正则表达式,则可以使用正则表达式(这有点要感谢while循环);因此,这个答案也适用于 [#[#a|b#]|b#] 之类的东西,但请注意,任何进一步的嵌套都将失败(如果它嵌套在单数一侧)。

<小时/>

代码

See regex in use here

\[#((?:\[#.*?#]|(?!#])[^|])*?)\|((?:\[#.*?#]|(?!#])[^|])*?)#]

用法

See code in use here

import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        String s = "Today [#[#item#] was|the items were#] shipped so [#it is|they are#] gone.";
        System.out.println(convert(s, true));
        System.out.println(convert(s, false));
    }

    public static String convert(String text, boolean isSingular) {
        Pattern spPattern = Pattern.compile("\\[#((?:\\[#.*?#]|(?!#])[^|])*?)\\|((?:\\[#.*?#]|(?!#])[^|])*?)#]");
        Matcher matcher = spPattern.matcher(text);
        while (matcher.find()) {
            String replacement = isSingular ? matcher.group(1) : matcher.group(2);
            text = matcher.replaceFirst(replacement);
            matcher = spPattern.matcher(text);
        }
        return text;
    }
}
<小时/>

说明

  • \[# 字面匹配 [#
  • ((?:\[#.*?#]|(?!#])[^|])*?) 将以下内容捕获到捕获组 1 中
    • (?:\[#.*?#]|(?!#])[^|])*? 匹配以下任意次数,但尽可能少
    • \[#.*?#] 匹配以下内容
      • \[# 字面匹配 [#
      • .*? 匹配任何字符任意次数,但尽可能少
      • #] 按字面意思匹配
    • (?!#])[^|] 匹配以下内容
      • (?!#]) 负向前瞻确保后面的内容与字面上的 #] 不匹配
      • [^|] 匹配除 | 之外的任何内容
  • \| 按字面意思匹配 |
  • ((?:\[#.*?#]|(?!#])[^|])*?) 将以下内容捕获到捕获组 2 中
    • 请参阅捕获组 1 下的说明(与捕获组 1 相同)
  • #] 字面匹配

关于java - 正则表达式中的负向前瞻匹配所有接受特定字符的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47910210/

相关文章:

C# 字符串的正则表达式

python - 如何使用否定先行删除两个字符之间的搜索

匹配字符串的正则表达式,但前提是同一行上的任何地方都不存在另一个字符串

python - 使用正则表达式匹配不以特定字母开头的单词

java - 迭代器删除/编辑是安全的,但是我还需要编辑以下所有迭代

java - Java中读取子目录和特定文件

python - 查找所有希腊文本中带连字符的单词

jquery - 密码强度不按规则工作

java - 如何通过 Mockito 模拟无法访问的第三方类属性

java - 如何返回 DataSnapshot 值作为方法的结果?