正则表达式匹配除给定列表之外的所有单词

时间:2008-10-28 09:51:47

标签: c# .net regex

我正在尝试编写一个替换正则表达式来包围引号中的所有单词,但单词AND,OR和NOT除外。

我已经尝试了以下表达式的匹配部分:

(?i)(?<word>[a-z0-9]+)(?<!and|not|or)

(?i)(?<word>[a-z0-9]+)(?!and|not|or)
但是没有工作。替换表达式很简单,目前包含所有单词。

"${word}"

所以

  

这和这不是

成为

  

“这个”和“这个”不是“那个”

6 个答案:

答案 0 :(得分:14)

这有点脏,但它有效:

(?<!\b(?:and| or|not))\b(?!(?:and|or|not)\b)

用简单的英语,这匹配任何不在前面的词边界,而不是“and”,“或”或“not”。它仅匹配整个单词,例如单词“sand”之后的位置不会是匹配,因为它前面是“and”。

零宽度后视断言中“或”前面的空间对于使其成为固定长度的后视是必要的。如果这已经解决了您的问题,请尝试。

编辑:应用于字符串“除了单词AND,OR和NOT。”作为单引号的全局替换,它返回:

'except' 'the' 'words' AND, OR and NOT.

答案 1 :(得分:5)

约翰,

你问题中的正则表达式几乎是正确的。唯一的问题是你将前瞻放在正则表达式的末尾而不是开头。此外,您需要添加单词边界以强制正则表达式匹配整个单词。否则,它将匹配“和”中的“nd”,“或”等中的“r”,因为“nd”和“r”不在您的负向前瞻中。

  

\ B(Ⅰ')(与|△!不|或)(?[A-Z0-9] +)\ B'/ P>

答案 2 :(得分:3)

叫我疯了,但我不是打正则表演者的粉丝;我将我的模式限制为我能理解的简单事物,并经常为其余部分作弊 - 例如通过MatchEvaluator

    string[] whitelist = new string[] { "and", "not", "or" };
    string input = "foo and bar or blop";
    string result = Regex.Replace(input, @"([a-z0-9]+)",
        delegate(Match match) {
            string word = match.Groups[1].Value;
            return Array.IndexOf(whitelist, word) >= 0
                ? word : ("\"" + word + "\"");
        });

(编辑更简洁的布局)

答案 3 :(得分:2)

根据Tomalaks回答:

(?<!and|or|not)\b(?!and|or|not)

这个正则表达式有两个问题:

  1. (?<! )仅适用于固定长度的后视

  2. 以前的正则表达式仅查看周围单词的结尾/开头,而不是整个单词。

  3.   

    (?<!\band)(?<!\bor)(?<!\bnot)\b(?!(?:and|or|not)\b)

    这个正则表达式修复了上述两个问题。首先将后视分为三个独立的后视镜。其次是在环顾中添加单词边界(\b)。

答案 4 :(得分:0)

(?!\bnot\b|\band\b|\bor\b|\b\"[^"]+\"\b)((?<=\s|\-|\(|^)[^\"\s\()]+(?=\s|\*|\)|$))

我使用此正则表达式查找不在双引号内的所有单词,或者单词“not”“和”或“或”。

答案 5 :(得分:0)

要匹配由字母,数字或下划线(包括\w shorthand character class中定义的任何其他单词字符)组成的任何“单词” ,您可以使用单词边界喜欢

\b(?!(?:word1|word2|word3)\b)\w+

如果“单词”是一大堆非空白字符,并且两端都是字符串的开头/结尾或空白,请使用空白边界,如

(?<!\S)(?!(?:word1|word2|word3)(?!\S))\S+

这两个表达式看起来像

\b(?!(?:and|not|or)\b)\w+
(?<!\S)(?!(?:and|not|or)(?!\S))\S+

请参见regex demo(或流行的regex101 demo,但请注意,PCRE \w的含义不同于.NET \w的含义。)

模式说明

  • \b-word boundary
  • (?<!\S)-向后查找的否定字符,匹配的位置不是紧随空格以外的其他字符,它需要字符串位置的开始或空白字符位于当前位置的正前方
  • (?!(?:word1|word2|word3)\b)-如果在当前位置的右侧紧邻有word1word2word3个char序列,则负匹配将使匹配失败单词边界(或,如果使用(?!\S)空格右边界,则必须在当前位置的右边紧接空格或字符串结尾)
  • \w+-1+ word chars
  • \S+-除whitespace以外的1个以上的字符

在C#和任何其他编程语言中,您可以通过将数组/列表项与管道字符(下面的see the demo)连接起来,来动态构建模式:

var exceptions = new[] { "and", "not", "or" };
var result = Regex.Replace("This and This not That", 
        $@"\b(?!(?:{string.Join("|", exceptions)})\b)\w+",
        "\"$&\"");
Console.WriteLine(result); // => "This" and "This" not "That"

如果您的“单词”可能包含特殊字符,则使用空格边界方法更为合适,并确保使用exceptions.Select(Regex.Escape)来转义“单词”:

var pattern = $@"(?<!\S)(?!(?:{string.Join("|", exceptions.Select(Regex.Escape))})(?!\S))\S+";

注意:如果要搜索的单词过多,则最好用它们构建一个 regex trie