【问题标题】:Extracting double quoted strings with escape sequences [duplicate]使用转义序列提取双引号字符串[重复]
【发布时间】:2018-03-17 19:46:08
【问题描述】:

我有一些表格文本:

This is some text, and here's some in "double quotes"
"and here's a double quote:\" and some more", "text that follows"

文本包含双引号内的字符串,如上所示。双引号可以用反斜杠 (\) 转义。在上面,有三个这样的字符串:

"double quotes"
"and here's a double quote:\" and some more"
"text that follows"

为了提取这些字符串,我尝试了正则表达式:

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

但是,这给了我以下结果:

>>> preg_match_all('%"(?:\\"|.)*?"%', $msg, $matches)
>>> $matches
[
  [ "double quotes",
    "and here's a double quote:\",
    ", "
  ]
]

如何正确获取字符串?

【问题讨论】:

  • 你几乎只是一个逃避问题。要转义反斜杠,您必须这样做'%"(?:\\\\"|.)*?"%'

标签: php regex parsing


【解决方案1】:

如果你echo your pattern, you'll see it's indeed passed as %"(?:\"|.)*?"% 到正则表达式解析器。即使是正则表达式解析器,单个反斜杠也会被视为转义字符。

因此,如果模式在单引号内,则您需要至少再添加一个反斜杠,以将两个反斜杠传递给解析器(一个用于转义反斜杠),该模式将是:%"(?:\\"|.)*?"%

preg_match_all('%"(?:\\\"|.)*?"%', $msg, $matches);

这仍然不是一个非常有效的模式。这个问题似乎实际上是一个duplicate of this one

有一个better pattern available in this answer(有些人会称之为unrolled)。

preg_match_all('%"[^"\\\]*(?:\\\.[^"\\\]*)*"%', $msg, $matches);

See demo at eval.in 或与其他模式比较步骤in regex101

【讨论】:

    【解决方案2】:

    一种方法是使用否定。回顾:

    ".*?(?<!\\)"
    


    PHP 中的哪个是:
    <?php
    
    $text = <<<TEXT
    This is some text, and here's some in "double quotes"
    "and here's a double quote:\" and some more", "text that follows"
    TEXT;
    
    $regex = '~".*?(?<!\\\\)"~';
    
    if (preg_match_all($regex, $text, $matches)) {
        print_r($matches);
    }
    ?>
    


    这产生
    Array
    (
        [0] => Array
            (
                [0] => "double quotes"
                [1] => "and here's a double quote:\" and some more"
                [2] => "text that follows"
            )
    
    )
    


    a demo on regex101.com
    要让它跨越多行,请通过以下方式启用dotall 模式
    "(?s:.*?)(?<!\\)"
    

    也请参阅a demo for the latter on regex101.com

    【讨论】:

    • 测试引号前面是否有反斜杠并不能证明任何事情。您不知道反斜杠本身是否被另一个反斜杠转义。 (换句话说,您不知道引号前的反斜杠数是奇数还是偶数)。
    • @CasimiretHippolyte:虽然这是真的,但在 OP 的问题中没有要求这样做。
    【解决方案3】:

    如果您让正则表达式捕获反斜杠字符作为字符,那么它将在“\”处终止您的捕获组(因为前面的 \ 被视为单个字符)。所以你需要做的是允许 \" 被捕获,但不是 \ 或 " 单独捕获。结果是以下正​​则表达式:

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

    Try it here!

    下面详细解释:

    "                begin with a single quote character
    (                capture only what follows (within " characters)
      (?:            don't break into separate capture groups
        [^"\\]*      capture any non-" non-\ characters, any number of times
        (?:\\")*     capture any \" escape sequences, any number of times
      )*             allow the previous two groups to occur any number of times, in any order
    )                end the capture group
    "                make sure it ends with a "
    

    请注意,在许多语言中,当将正则表达式字符串提供给方法以解析某些文本时,您需要转义反斜杠字符、引号等。在 PHP 中,上述内容将变为:

    '/"((?:[^"\\\\]*(?:\\\\")*)*)"/'
    

    【讨论】:

    • 不幸的是,这给了我一个missing terminating ] for character classrepl.it/repls/RecklessConstantLesson
    • @user2064000 使用 PHP,您必须转义反斜杠:'/"(?:(?:[^"\\\\])*(?:\\\\")*)*"/'
    • @Syscall,是的,把它们和 bash 语法搞混了。
    • 所有不必要的非捕获组是怎么回事?组成本步骤。
    • 这或多或少是正确的(因为它不处理不是引号的转义字符),但请删除所有这些无用的组。
    猜你喜欢
    • 2019-01-24
    • 1970-01-01
    • 2014-09-26
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 2013-01-06
    相关资源
    最近更新 更多