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

时间:2017-12-20 16:11:07

标签: java regex negative-lookahead

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

给出以下字符串:

Today [#[#item#] was|the items were#] shipped so [#it is|they are#] gone.

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

Today [#item#] was shipped so it is gone.Today the items were shipped so they are gone

我正在尝试在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的第一次迭代之后是Today [#item#] was shipped so [#it is|they are#] gone.,这没关系。但是,在第二次迭代中,Matcher与小组[#item#] was shipped so [#it is|they are#]匹配,而[#it is|they are#]应该是(\\[#.*?\\|.*?#\\])(?!\\[#[^\\|]*?#\\])。我很确定我需要某种负面的前瞻。

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

terminal.sendText(command); vscode.commands.executeCommand( "workbench.files.action.refreshFilesExplorer" ); (“尝试匹配[#和#]之间的所有内容,接受那些不包含这些标签之间的情况的情况”)

我错过了什么?

2 个答案:

答案 0 :(得分:0)

您遇到的问题是因为您的第一次替换正在生成Today [#item#] was shipped so [#it is|they are#] gone.且您的正则表达式与[#item#] was shipped so [#it is|they are#]匹配。然后你的正则表达式错误地替换了这个字符串。

解决这个问题的 true 方法是创建一个解析器,但是如果函数以递归方式运行正则表达式(它是 的种类确实归功于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相同)
  • #]按字面意思匹配

答案 1 :(得分:0)

这是伪代码,显示了可以这样做的方法 显然我不懂Java。

regex_main = "(?s)(.*?)((?=\\[\\#)(?:(?=.*?\\[\\#(?!.*?\\3)(.*\\#\\](?!.*\\4).*))(?=.*?\\#\\](?!.*?\\4)(.*)).)+?.*?(?=\\3)(?:(?!\\[\\#).)*)(?=\\4)|(.+)"

regex_brack_contents = "(?s)^\\[\\#(.*)\\#\\]$"

sTemplate = "Today [#[#item#] was|the items were#] shipped so [#it is|they are#] gone."
sOut[5] = ""
nPermutations = 0
Matcher _M = regex_main.matcher( sTemplate );

while ( _M.find() ) {
    if ( _M.group(1) ) {
        for (i = 0; i < 5; i++ ) 
            sOut[i] += _M.group(1)
        Matcher _m = regex_brack_contents.matcher( _M.group(2) )
        if ( _m.find() ) {
            aray = _m.group(1).split("|");
            for ( i = 0; i < sizeof(aray), i < 5; i++ )
                sOut[i] += aray[i]
            if ( i > nPermutations )
                nPermutations = i
        }
    }
    else { 
        for (i = 0; i < 5; i++ ) 
           sOut[i] += _M.group(5)
    }
    _M = regex_main.matcher( sTemplate );
}
for (i = 0; i < nPermutations; i++ ) 
    print( sOut[i] + "\r\n" )