【问题标题】:How to match something with regex that is not between two special characters?如何匹配不在两个特殊字符之间的正则表达式?
【发布时间】:2012-07-15 04:47:38
【问题描述】:

我有一个这样的字符串:

a b c a b " a b " b a " a "

如何匹配不属于由" 分隔的字符串的每个a?我想匹配这里所有的粗体:

a bc a b "ab" b a "a"

我想替换这些匹配项(或者通过将它们替换为空字符串来删除它们),因此删除带引号的部分进行匹配是行不通的,因为我希望它们保留在字符串中。我正在使用 Ruby。

【问题讨论】:

  • 一个正则表达式一次匹配一个子字符串。如何循环正则表达式是宿主语言的一个特性。您使用哪种语言?

标签: ruby regex


【解决方案1】:

js-coder,复活了这个古老的问题,因为它有一个没有提到的简单解决方案。 (在为regex bounty quest 做一些研究时发现了你的问题。)

正如您所看到的,与已接受答案中的正则表达式相比,正则表达式非常小:("[^"]*")|a

subject = 'a b c a b " a b " b a " a "'
regex = /("[^"]*")|a/
replaced = subject.gsub(regex) {|m|$1}
puts replaced

看到这个live demo

参考

How to match pattern except in situations s1, s2, s3

How to match a pattern unless...

【讨论】:

  • 意外点赞。这个答案是不正确的,因为它也会完全匹配引用的部分,而不是只匹配字符串之外的 'a' 字符。接受的答案按预期工作。
【解决方案2】:

假设引号正确平衡并且没有转义引号,那么很容易:

result = subject.gsub(/a(?=(?:[^"]*"[^"]*")*[^"]*\Z)/, '')

当且仅当匹配的 a 前面有偶数个引号时,这会将所有 as 替换为空字符串。

说明:

a        # Match a
(?=      # only if it's followed by...
 (?:     # ...the following:
  [^"]*" #  any number of non-quotes, followed by one quote
  [^"]*" #  the same again, ensuring an even number
 )*      # any number of times (0, 2, 4 etc. quotes)
 [^"]*   # followed by only non-quotes until
 \Z      # the end of the string.
)        # End of lookahead assertion

如果您可以在引号内转义引号 (a "length: 2\""),这仍然是可能的,但会更复杂:

result = subject.gsub(/a(?=(?:(?:\\.|[^"\\])*"(?:\\.|[^"\\])*")*(?:\\.|[^"\\])*\Z)/, '')

这本质上与上面的正则表达式相同,只是将(?:\\.|[^"\\]) 替换为[^"]

(?:     # Match either...
 \\.    # an escaped character
|       # or
 [^"\\] # any character except backslash or quote
)       # End of alternation

【讨论】:

    【解决方案3】:

    为正则表达式爱好者提供成熟的正则表达式解决方案,无需关心性能或代码可读性。

    此解决方案假定没有转义语法(使用转义语法,"sbd\"a" 中的 a 被计入字符串内部)。

    伪代码:

    processedString = 
        inputString.replaceAll("\\".*?\\"","") // Remove all quoted strings
                   .replaceFirst("\\".*", "") // Consider text after lonely quote as inside quote
    

    然后你就可以在processedString中匹配你想要的文字了。如果您将单引号后的文本视为外引号,则可以删除第二个替换。

    编辑

    在 Ruby 中,上面代码中的正则表达式是

    /\".*?\"/
    

    gsub一起使用

    /\".*/
    

    sub一起使用


    为了解决更换问题,我不确定这是否可行,但值得尝试:

    • 声明一个计数器
    • 将正则表达式 /(\"|a)/ 与 gsub 和提供函数一起使用。
    • 在函数中,如果匹配为",则递增计数器,并返回"作为替换(基本上没有变化)。如果匹配是a 检查计数器是否为偶数:如果偶数提供您的替换字符串;否则,只需提供匹配的内容。

    【讨论】:

    • 这与 OP 要求中提到的 'a' 有什么关系吗?
    • @ElRonnoco:是的。我不是一次做所有事情,而是删除所有带引号的字符串,只在processedString 中留下未加引号的部分。然后搜索文本将很容易。不过,我的解决方案有假设。
    • 我的错,我想先匹配它们,然后再替换它们。但我希望引用的部分保留在字符串中。您要删除引用的部分,然后匹配所有as 对吗?
    • 我认为 Ruby 没有g 标志。
    • @dotweb:另一种解决方案是将" 替换为您确定不会出现在输入字符串中的特殊字符,但这是非常hacky 的解决方案,我不推荐它。跨度>
    猜你喜欢
    • 2023-04-10
    • 2017-02-16
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-26
    • 2019-12-28
    相关资源
    最近更新 更多