我正试图编写一个替换正则表达式,用引号包围除了AND、OR和NOT之外的所有单词。
以下是我尝试过的匹配部分表达式:
(?i)(?<word>[a-z0-9]+)(?<!and|not|or)
(?i)(?<word>[a-z0-9]+)(?!and|not|or)
但是两者都不起作用。替换表达式很简单,目前将所有单词都包含在内。
"${word}"
因此
这个和这个不是那个
变成
“这个”和“这个”不是“那个”
我正试图编写一个替换正则表达式,用引号包围除了AND、OR和NOT之外的所有单词。
以下是我尝试过的匹配部分表达式:
(?i)(?<word>[a-z0-9]+)(?<!and|not|or)
(?i)(?<word>[a-z0-9]+)(?!and|not|or)
但是两者都不起作用。替换表达式很简单,目前将所有单词都包含在内。
"${word}"
因此
这个和这个不是那个
变成
“这个”和“这个”不是“那个”
这有点不太规范,但却可行:
(?<!\b(?:and| or|not))\b(?!(?:and|or|not)\b)
用简单明了的语言来说,这个正则表达式匹配任何一个不以 "and"、"or" 或 "not" 开头或结尾的单词边界。它只匹配整个单词,例如在单词 "sand" 后面的位置不会匹配,因为它前面有 "and"。
在零宽度向后查找断言中,在 "or" 前面加上空格是必须的,这样它就成为了一个固定长度的向后查找。尝试一下是否已经解决了你的问题。
编辑:对于字符串 "except the words AND, OR and NOT." 进行全局替换并用单引号括起来,这将返回:
'except' 'the' 'words' AND, OR and NOT.
约翰,
你的正则表达式几乎正确。唯一的问题是你把前瞻放在了正则表达式的结尾而不是开头。此外,你需要添加单词边界以强制正则表达式匹配整个单词。否则,它会匹配“and”中的“nd”,“or”中的“r”等,因为“nd”和“r”不在你的负前瞻中。
(?i)\b(?!and|not|or)(?[a-z0-9]+)\b
[a-z]
而不是 \pL
或 \p{Alphabetic}
或有时候是 [[:alpha:]]
在我们后 7 位时代几乎总是太“20世纪60年代”了。第二,我发现人们经常误解什么是 \b,因此最近我在推荐时一直添加关于它的注意事项。 (是的,我知道 你 当然都理解这些,Jan,但很多读者可能不理解。) - tchrist不知道是否有点疯狂,但我并不喜欢去对抗正则表达式;我只使用一些简单易懂的模式,并且通常会通过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 + "\"");
});
(edited for more terse layout)
\w
简写字符类中定义的其他单词字符)组成的"单词",您可以使用像单词边界这样的符号。\b(?!(?:word1|word2|word3)\b)\w+
(?<!\S)(?!(?:word1|word2|word3)(?!\S))\S+
\b(?!(?:and|not|or)\b)\w+
(?<!\S)(?!(?:and|not|or)(?!\S))\S+
\w
的含义与.NET \w
的含义不同。)
模式解释
\b
- 单词边界(?<!\S)
- 一个负向零宽断言,匹配不紧跟非空格字符的位置,它要求当前位置的左边是字符串的开头或者一个空白字符(?!(?:word1|word2|word3)\b)
- 一个负向前瞻,如果当前位置的右边是紧跟着一个单词边界的word1
、word2
或word3
字符序列,则匹配失败(或者,如果使用了(?!\S)
表示右侧边界是空白符或字符串结尾,则当前位置的右侧必须紧跟着一个空白符或字符串结尾)\w+
- 匹配1个或多个单词字符\S+
- 匹配1个或多个非空白符字符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+";
根据Tomalaks的答案:
(?<!and|or|not)\b(?!and|or|not)
(?<! )
仅适用于固定长度的后顾断言。
之前的正则表达式只查看了周围单词的结尾/开头,而不是整个单词。
这个正则表达式解决了上述两个问题。首先通过将后顾断言分成三个单独的部分来解决第一个问题。其次,在环视中添加了单词边界(
(?<!\band)(?<!\bor)(?<!\bnot)\b(?!(?:and|or|not)\b)
\b
)以解决第二个问题。(?!\bnot\b|\band\b|\bor\b|\b\"[^"]+\"\b)((?<=\s|\-|\(|^)[^\"\s\()]+(?=\s|\*|\)|$))
我使用这个正则表达式来查找所有不在双引号内的单词,或者是单词 "not"、"and" 或 "or"。