【问题标题】:regex match keywords that are not in quotes正则表达式匹配不在引号中的关键字
【发布时间】:2012-07-22 03:28:03
【问题描述】:

如何查找不在字符串中的关键字。

例如,如果我有文字:

你好,本文是一个例子。

bla bla bla "此文本在字符串中"

"随机字符串" more text bla bla bla "foo"

我希望能够匹配所有不在" " 中的单词text。在其他我想匹配:

注意我不想匹配以红色突出显示的文本,因为它在字符串中


可能的解决方案:

我一直在努力,这就是我目前所拥有的:

(?s)((?<q>")|text)(?(q).*?"|)

请注意,正则表达式将 if 语句用作:(?(predicate) true Alternative|false Alternative)

因此正则表达式将显示为:

找到 " 或文本。如果找到 " 然后继续选择直到再次找到 " (.*?") 如果找到文本则什么也不做...

当我运行该正则表达式时,我匹配整个字符串。我问这个问题是为了学习。我知道我可以删除所有字符串然后查找我需要的内容。

【问题讨论】:

  • 您是否尝试过在线正则表达式生成器,例如:txt2re.com/index-csharp.php3
  • 为什么要匹配一个你知道的字符串?你打算如何处理结果。意图对于其他人能够给出适当的答案很重要。
  • 你不需要知道问题的意图就能回答它。您还假设他知道字符串是什么。他只是举例说明他正在尝试做什么,而这些不一定是他最终会使用的。他正在寻找一个特定的结果,如何使用该结果与我们无关。

标签: c# regex parsing


【解决方案1】:

这是一个答案:

(?<=^([^"]|"[^"]*")*)text

这意味着:

(?<=       # preceded by...
^          # the start of the string, then
([^"]      # either not a quote character
|"[^"]*"   # or a full string
)*         # as many times as you want
)
text       # then the text

您也可以轻松扩展它以处理包含转义的字符串。

在 C# 代码中:

Regex.Match("bla bla bla \"this text is inside a string\"",
            "(?<=^([^\"]|\"[^\"]*\")*)text", RegexOptions.ExplicitCapture);

从评论讨论中添加 - 扩展版本(基于每行匹配并处理转义)。为此使用RegexOptions.Multiline

(?<=^([^"\r\n]|"([^"\\\r\n]|\\.)*")*)text

在 C# 字符串中,如下所示:

"(?<=^([^\"\r\n]|\"([^\"\\\\\r\n]|\\\\.)*\")*)text"

既然您现在想使用 ** 而不是 ",这里有一个版本:

(?<=^([^*\r\n]|\*(?!\*)|\*\*([^*\\\r\n]|\\.|\*(?!\*))*\*\*)*)text

解释:

(?<=       # preceded by
^          # start of line
 (         # either
 [^*\r\n]| #  not a star or line break
 \*(?!\*)| #  or a single star (star not followed by another star)
  \*\*     #  or 2 stars, followed by...
   ([^*\\\r\n] # either: not a star or a backslash or a linebreak
   |\\.        # or an escaped char
   |\*(?!\*)   # or a single star
   )*          # as many times as you want
  \*\*     # ended with 2 stars
 )*        # as many times as you want
)
text      # then the text

由于此版本不包含 " 字符,因此使用文字字符串更简洁:

@"(?<=^([^*\r\n]|\*(?!\*)|\*\*([^*\\\r\n]|\\.|\*(?!\*))*\*\*)*)text"

【讨论】:

  • Porges 感谢您的帮助!如果我在哪里有:" \r\n text \r\n " bla bla... 不匹配...我想原因是因为[^"] 将继续下一行...
  • @TonoNam:如果您希望它在每行的基础上进行匹配,请将[^"] 更改为[^"\r\n] 并将RegexOptions.Multiline 添加到选项中。
  • "(?&lt;=^([^\"]|\"[^\"]*\")*)text" 如果引用的文本后面有任何文本,则不起作用。
  • 很好的解决方案,但是当引用的字符串是多行并且匹配的单词在新行上时不起作用:regex101.com/r/UhAi9f/1
【解决方案2】:

这可能会变得非常棘手,但这是一种可能的方法,它可以确保匹配文本和字符串结尾之间有偶数个引号:

text(?=[^"]*(?:"[^"]*"[^"]*)*$)

text 替换为您要匹配的正则表达式。

Rubular:http://www.rubular.com/r/cut5SeWxyK

解释:

text            # match the literal characters 'text'
(?=             # start lookahead
   [^"]*          # match any number of non-quote characters
   (?:            # start non-capturing group, repeated zero or more times
      "[^"]*"       # one quoted portion of text
      [^"]*         # any number of non-quote characters
   )*             # end non-capturing group
   $              # match end of the string
)               # end lookahead

【讨论】:

    【解决方案3】:

    我会简单地贪婪地匹配非捕获组中的引号中的文本以将它们过滤掉,然后将捕获组用于未引用的答案,如下所示:

    ".*(?:text).*"|(text)
    

    您可能希望针对单词边界等进行一些改进。但这应该可以让您到达您想去的地方,并且是一个清晰易读的示例。

    【讨论】:

      【解决方案4】:

      到目前为止,我已经多次使用这些答案,并希望分享解决此问题的替代方法,因为有时我无法实施和使用给定的答案。

      与其匹配关键字,不如将任务分解为两个子任务:

      1. 将不需要匹配的所有内容替换为空字符串
      2. 使用普通匹配

      例如,要替换我使用的引号中的文本:

      [dbo].[fn_Utils_RegexReplace] ([TSQLRepresentation_WHERE], '''.*?(?<!\\)''', '')
      

      或更清楚:'.*?(?&lt;!\\)'

      我知道这可能看起来像双重工作并且对某些平台/语言有性能影响,所以每个人也需要对此进行测试。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多