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

C# 正则表达式匹配除给定列表外的所有单词,c#,.net,regex,C#,.net,Regex,我正在尝试编写一个替换正则表达式,将除AND、OR和NOT之外的所有单词用引号括起来 对于表达式的匹配部分,我尝试了以下操作: (?i)(?<word>[a-z0-9]+)(?<!and|not|or) 所以 这个不是那个 变成 “这个”和“这个”不是“那个” 这有点脏,但它可以工作: (?<!\b(?:and| or|not))\b(?!(?:and|or|not)\b) 你可以说我疯了,但我不喜欢和regex打架;我将我的模式限制在我能理解的简单事情上,并且经常为

我正在尝试编写一个替换正则表达式,将除AND、OR和NOT之外的所有单词用引号括起来

对于表达式的匹配部分,我尝试了以下操作:

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

这个不是那个

变成

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


这有点脏,但它可以工作:

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

你可以说我疯了,但我不喜欢和regex打架;我将我的模式限制在我能理解的简单事情上,并且经常为其他事情作弊-例如通过
匹配评估器

    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 + "\"");
        });

(为了更简洁的布局而编辑)

基于Tomalak的答案:

(?<!and|or|not)\b(?!and|or|not)
(?
此正则表达式有两个问题:

  • (?仅适用于固定长度后视镜

  • 前面的正则表达式只查看周围单词的结尾/开头,而不是整个单词

  • 此正则表达式修复了上述两个问题。首先,将“后向查找”拆分为三个单独的问题。其次,在“后向查找”中添加单词边界(
    \b

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

    (?i)\b(?)和|非|或(?[a-z0-9]+)\b

    (?!\bnot\b | \band\b | \bor\b | \b\“[^”]+\”\b)((?要匹配任何由字母、数字或下划线组合而成的“单词”(包括中定义的任何其他单词字符),可以使用单词边界

    \b(?!(?:word1|word2|word3)\b)\w+
    
    (?<!\S)(?!(?:word1|word2|word3)(?!\S))\S+
    
    如果“单词”是一组非空白字符,字符串开头/结尾或两端都是空白,请使用空白边界,如中所示

    \b(?!(?:word1|word2|word3)\b)\w+
    
    (?<!\S)(?!(?:word1|word2|word3)(?!\S))\S+
    
    如果您的“单词”可能包含特殊字符,则空格边界方法更合适,并确保使用异常来转义“单词”。选择(Regex.escape)


    var pattern=$@”(?你能给出样本输入和预期结果(匹配与否)?(?i)(?[a-z0-9]++)(?不幸的是,它是dot net 2,所以没有lambda只是yetFine,我将为C#2.0进行编辑(你指的是C#2.0,不是.net 2.0;你可以将它与C#3.0和.net 2.0一起使用)不,这不是懒惰。这是一个很好的保持表达式可维护的方法。+1表示很少听到的智慧。:)唯一可能失败的情况是字符串以“或”开头。好的,它包含一个隐藏的假设,即空格分隔单词。如果您知道数据,这两种情况都可以迁移。与所有正则表达式一样,这很疯狂,但它可以工作。(?[a-z0-9]+)(?您需要什么“(?[a-z0-9]+)”因为?你是想用引号括住你的单词还是想把它们从字符串中拔出来?对于以任何给定单词结尾或开头的单词来说,这都是失败的。“你好,不是再见”->““你好,不是再见”是的。谢谢你的提示,我扩展了正则表达式来解释这一点。是的,其他人正在使这一点变得比它需要的复杂得多。特别是,没有必要使用负面(或正面)外观或命名捕获。两件事:首先,我得出的结论是,指定文字
    [a-z]
    而不是
    \pL
    \p{alphatic}
    或有时
    [:alpha:]
    在我们的后7位时代,几乎总是太“60年代”了。其次,我发现人们,所以最近每当我推荐它时,我都会在它的gotchas上添加一些限制性条款。(是的,我知道你当然明白这一切,简,但许多读者可能不明白。)
    \b(?!(?:word1|word2|word3)\b)\w+
    
    (?<!\S)(?!(?:word1|word2|word3)(?!\S))\S+
    
    \b(?!(?:and|not|or)\b)\w+
    (?<!\S)(?!(?:and|not|or)(?!\S))\S+
    
    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"
    
    var pattern = $@"(?<!\S)(?!(?:{string.Join("|", exceptions.Select(Regex.Escape))})(?!\S))\S+";