代码之家  ›  专栏  ›  技术社区  ›  deadbug

正则表达式:在引号之间获取值

  •  169
  • deadbug  · 技术社区  · 17 年前

    我有这样一个价值观:

    "Foo Bar" "Another Value" something else
    

    什么正则表达式将返回引号中包含的值(例如。 Foo Bar Another Value

    19 回复  |  直到 12 年前
        1
  •  434
  •   Community Mohan Dere    9 年前

    (["'])(?:(?=(\\?))\2.)*?\1
    

    对于那些想要更深入地解释其工作原理的人,这里有一个来自用户的解释 ephemient

    ([""']) 匹配报价; ((?=(\\?))\2.) *? 多次匹配(不贪吃,以免吃收盘价); \1 匹配用于开始的相同报价。

        2
  •  412
  •   Rodrigo Deodoro    13 年前

    "(.*?)"
    

    这使用了非贪婪*?操作员将捕获到但不包括下一个双引号的所有内容。然后,使用特定于语言的机制提取匹配的文本。

    在Python中,您可以执行以下操作:

    >>> import re
    >>> string = '"Foo Bar" "Another Value"'
    >>> print re.findall(r'"(.*?)"', string)
    ['Foo Bar', 'Another Value']
    
        3
  •  112
  •   Loki Astari    17 年前

    "([^"]*)"
    

    这个 是除' '
    我之所以在非贪心多运算符上使用它,是因为我必须不断地查找它,以确保它是正确的。

        4
  •  33
  •   Casimir et Hippolyte    9 年前

    让我们看看处理转义引号的两种有效方法。这些图案的设计既不简洁也不美观,而是高效的。

    这些方法使用第一个字符区分来快速查找字符串中的引号,而无需进行替换。 (这样做的目的是在不测试交替的两个分支的情况下,快速丢弃不是引号的字符。)

    引号之间的内容采用展开循环(而不是重复交替)进行描述,以提高效率: [^"\\]*(?:\\.[^"\\]*)*

    显然,要处理没有平衡引号的字符串,可以使用所有格量词: [^"\\]*+(?:\\.[^"\\]*)*+ 或者是一种变通方法来模仿它们,以防止太多的回溯。您也可以选择,在下一个(非转义)引号或字符串结束之前,带引号的部分可以是起始引号。在这种情况下,不需要使用所有格量词,只需将最后一个引号设置为可选。

    注意:有时引号不是用反斜杠转义的,而是通过重复引号转义的。在这种情况下,内容子模式如下所示: [^"]*(?:""[^"]*)*

    )我是说 (["']).....\1 ) 并使用一个简单的替代,但与 ["'] 在开始时,在因子中。

    类似Perl:

    ["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
    

    (注意 (?s:...) [\s\S]

    (此模式的编写方式完全是“手动”的,不考虑最终的引擎内部优化)

    ECMA脚本:

    (?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
    

    POSIX扩展:

    "[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
    

    或者简单地说:

    "([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
    
        5
  •  26
  •   IrishDubGuy    8 年前

    特别的是,这些答案都不会生成一个正则表达式,其中返回的匹配项是引号内的文本,这就是所要求的。马马登尝试了一下,但只把内线比赛作为一个被俘虏的小组,而不是整场比赛。实际做到这一点的一种方法是:

    (?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)
    

    这方面的例子可以在这个演示中看到 https://regex101.com/r/Hbj8aP/1

    这里的关键是开始时的积极回顾( ?<= )以及结尾处的正向前瞻( ?= ["'] (?=\1)

    唯一的另一个复杂之处是,因为先行查找实际上并不使用结束引号,所以它将被起始先行查找再次找到,从而导致同一行上结束引号和起始引号之间的文本匹配。在开头的引语中添加单词边界( ["']\b

        6
  •  23
  •   Martin Schneider    9 年前

    accepted answer的正则表达式返回值,包括它们的双引号: "Foo Bar" "Another Value" 像火柴一样。

    值介于

    只有双引号 (使用捕获组#1的值):

    "(.*?[^\\])"

    单引号 (使用捕获组#1的值):

    '(.*?[^\\])'

    (["'])(.*?[^\\])\1

    -

    所有支持转义引号和嵌套引号。

        7
  •  12
  •   Suganthan Madhavan Pillai    11 年前
        8
  •  10
  •   wp78de    6 年前

    我喜欢 Eugen Mihailescu's solution 匹配引号之间的内容,同时允许转义引号。但是,我发现了一些转义问题,并提出了以下正则表达式来解决这些问题:

    (['"])(?:(?!\1|\\).|\\.)*\1
    

    它做到了这一点,并且仍然非常简单,易于维护。

    Demo


    附言:如果你只是想要内容 之间 $0 ),并且不怕使用性能惩罚:

    (?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)
    

    不幸的是,没有引号作为锚,我不得不添加一个边界 \b 它不能很好地处理起始引号后的空格和非单词边界字符。

    group and extract the string form $2

    (['"])((?:(?!\1|\\).|\\.)*)\1
    

    PPS:如果你只关注效率,那就用 Casimir et Hippolyte's solution ; 这是一个好的。

        9
  •  8
  •   Eugen Mihailescu    10 年前

    (["'])(?:(?=(\\?))\2.)*?\1 上面的工作确实很好,但我担心它的表现(不错,但可能更好)。在它下面的矿井大约快20%。

    模式 "(.*?)" 只是不完整。我给每个读这篇文章的人的建议就是不要使用它!!!

    例如,它不能捕获许多字符串(如果需要,我可以提供一个详尽的测试用例),如下所示:

    $string='你好吗?我 \'

    其余的都和上面的一样“好”。

    如果您真的关心性能和精度,请从以下内容开始:

    /(['"])((\\\1|.)*?)\1/gm

    在我的测试中,它覆盖了我遇到的每一个字符串,但是如果你发现一些不起作用的东西,我很乐意为你更新它。

    Check my pattern in an online regex tester

        10
  •  6
  •   Axeman    12 年前

    这个版本

    • 转义引号的帐户
    • /(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
      
        11
  •  5
  •   HamZa    12 年前

    foo "string \\ string" bar
    

    foo "string1"   bar   "string2"
    

    正确,所以我尝试修复它:

    # opening quote
    (["'])
       (
         # repeat (non-greedy, so we don't span multiple strings)
         (?:
           # anything, except not the opening quote, and not 
           # a backslash, which are handled separately.
           (?!\1)[^\\]
           |
           # consume any double backslash (unnecessary?)
           (?:\\\\)*       
           |
           # Allow backslash to escape characters
           \\.
         )*?
       )
    # same character as opening quote
    \1
    
        12
  •  5
  •   James Harrington    9 年前

    \"([^\"]*?icon[^\"]*?)\"

    太长,读不下去了
    替换这个词 偶像 用你所说的话和瞧,寻找!


    其工作方式是查找关键字,而不关心引号之间的其他内容。
    id="fb-icon"
    id="icon-close"
    id="large-icon-close"
    "
    然后它寻找任何可能的一组不是 "
    直到它发现 icon
    以及任何可能的一组不是 "
    "

        13
  •  4
  •   Alan Moore Chris Ballance    12 年前
    string = "\" foo bar\" \"loloo\""
    print re.findall(r'"(.*?)"',string)
    

    试试这个,效果很好!!!

    \ 指示跳过字符

        14
  •  2
  •   lon    8 年前

    与亚当的答案不同,我有一个简单但有效的答案:

    (["'])(?:\\\1|.)*?\1
    

    如果您想获得如下引号中的内容,只需添加括号:

    (["'])((?:\\\1|.)*?)\1
    

    然后 $1 匹配引号char和 $2 匹配内容字符串。

        15
  •  1
  •   amo-ej1    17 年前
    echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'
    

    这将导致:>富吧<&燃气轮机<&燃气轮机;但这<

    这里我显示了介于><'为了清楚起见,也使用非贪婪版本的sed命令,我们首先抛出“”之前和之后的垃圾,然后用“”之间的部分替换它,并用><'s

        16
  •  1
  •   motoprog    14 年前

    从格雷格H。我能够创建这个正则表达式,以满足我的需要。

    我需要匹配一个特定的值,该值通过内部引号限定。它必须是完全匹配,任何部分匹配都不能触发命中

    reg = r"""(['"])(%s)\1"""
    if re.search(reg%(needle), haystack, re.IGNORECASE):
        print "winning..."
    

    猎人

        17
  •  1
  •   OffensivelyBad    8 年前

    \"([^\"]*?[^\"]*?)\".localized

    哪里 .localized 是后缀。

    例子:

    print("this is something I need to return".localized + "so is this".localized + "but this is not")

    "this is something I need to return".localized "so is this".localized 但不是 "but this is not" .

        18
  •  1
  •   S Meaden    8 年前

    关于子集合的补充答案 仅限Microsoft VBA编码器 Microsoft VBScript Regular Expressions 5.5 这给出了下面的代码

    Sub TestRegularExpression()
    
        Dim oRE As VBScript_RegExp_55.RegExp    '* Tools->References: Microsoft VBScript Regular Expressions 5.5
        Set oRE = New VBScript_RegExp_55.RegExp
    
        oRE.Pattern = """([^""]*)"""
    
    
        oRE.Global = True
    
        Dim sTest As String
        sTest = """Foo Bar"" ""Another Value"" something else"
    
        Debug.Assert oRE.test(sTest)
    
        Dim oMatchCol As VBScript_RegExp_55.MatchCollection
        Set oMatchCol = oRE.Execute(sTest)
        Debug.Assert oMatchCol.Count = 2
    
        Dim oMatch As Match
        For Each oMatch In oMatchCol
            Debug.Print oMatch.SubMatches(0)
    
        Next oMatch
    
    End Sub
    
        19
  •  1
  •   Donovan P    6 年前

    它们不支持所有unicode字符!

    如果您是节点用户,则可能需要支持所有unicode字符的已接受答案的修改版本:

    /(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu
    

    尝试 here

        20
  •  0
  •   HamZa    12 年前

    对我来说,这是一个:

    |([\'"])(.*?)\1|i
    

    我用过这样一句话:

    preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);
    

    而且效果很好。