【问题标题】:How can I extract a substring enclosed in double quotes in Perl?如何在 Perl 中提取用双引号括起来的子字符串?
【发布时间】:2020-06-26 17:17:38
【问题描述】:

我是 Perl 和正则表达式的新手,我很难提取用双引号括起来的字符串。比如,

“堆栈溢出是 惊人的”

在我提取字符串之前,我想检查它是否是整个文本的行尾是否在变量中:

if($wholeText =~ /\"$/)   #check the last character if " which is the end of the string
{
   $wholeText =~ s/\"(.*)\"/$1/;   #extract the string, removed the quotes
}

我的代码不起作用;它没有进入if 条件。

【问题讨论】:

  • 快速让自己看起来不像个菜鸟:正确地将语言称为 Perl。
  • 谢谢,但很困惑,有人告诉我应该使用 PERL 而不是 Perl。
  • 有些人错了——是 Perl。
  • 这和那个有什么不同:stackoverflow.com/questions/1479565/…
  • @Manni:没有什么不同。投票结束。

标签: regex perl


【解决方案1】:

你需要做的:

if($wholeText =~ /"$/)
{
    $wholeText =~ s/"(.*?)"/$1/s;
}

. 不匹配换行符,除非您应用 /s 修饰符。

没有必要像你一样转义引号。

【讨论】:

    【解决方案2】:

    上面推荐在正则表达式中使用“m”标志的发帖人是正确的,但是提供的正则表达式不太适用。当你说:

    $wholeText =~ s/\"(.*)\"/$1/m;   #extract the string, removed the quotes
    

    ...正则表达式过于“贪婪”,这意味着 (.*) 部分会吞噬过多的文本。如果你有这样的样本:

    "The quick brown fox," he said, "jumped over the lazy dog."
    

    ...那么上面的正则表达式将捕获从“The”到“dog.”的所有内容,这可能不是您想要的。有两种方法可以使正则表达式不那么贪婪。哪个更好与您选择如何处理字符串中的额外 " 标记有关。

    一个:

    $wholeText =~ s/\"([^"]*)\"/$1/m;
    

    两个:

    $wholeText =~ s/\"(.*?)\"/$1/m;
    

    在 One 中,正则表达式说“从引用开始,然后找到所有不是引用的内容并记住它,直到你看到另一个引用。”在二中,正则表达式表示“从引用开始,然后查找所有内容,直到找到另一个引用。”额外的? ( ) 内部告诉正则表达式处理器不要贪心。如果不考虑字符串中的引号转义,两个正则表达式的行为应该相同。

    顺便说一句,这是解析 CSV(“逗号分隔值”)文件时的一个经典问题,因此查找一些相关参考资料可能会对您有所帮助。

    【讨论】:

    • 我不认为 /m 做你认为它做的事。如果您的正则表达式中没有锚 ^ 或 $,则 /m 什么也不做。
    【解决方案3】:

    如果要将匹配项锚定到字符串的最末尾(不是行,整个字符串),请使用 \z 锚:

     if( $wholeText =~ /"\z/ ) { ... }
    

    您不需要为此设置保护条件。只需在替换中使用正确的正则表达式。如果它与正则表达式不匹配,则不会发生任何事情:

     $wholeText =~ s/"(.*?)"\z/$1/s;
    

    我认为您确实有一个不同的问题。你为什么要把它锚定到字符串的末尾?你想避免什么问题?

    【讨论】:

      【解决方案4】:

      对于多行字符串,您需要在搜索模式中包含“m”修饰符。

      if ($wholeText =~ m/\"$/m) # First m for match operator; second multi-line modifier
      {
           $wholeText =~ s/\"(.*?)\"/$1/s;   #extract the string, removed the quotes
      }
      

      您还需要考虑是否允许在字符串中使用双引号,如果允许,使用哪种约定。主要的是反斜杠和双引号(也是反斜杠反斜杠),或字符串中的双引号双引号。这些会使您的正则表达式稍微复杂化。

      @chaos 的答案使用“s”作为多行modifier。两者有一点区别:

      将字符串视为多行。也就是说,将“^”和“$”从匹配字符串的开头或结尾更改为匹配字符串中任何位置的任何行的开头或结尾。

      • s

      将字符串视为单行。即改“.”。匹配任何字符,甚至是换行符,通常它不会匹配。

      一起使用,如/ms,它们让“。”匹配任何字符,同时仍然允许 "^" 和 "$" 分别匹配字符串中的换行符之后和之前。

      【讨论】:

      • @Brian:第二个表达式中的问号有什么作用? AFAICS,它的意思是0或0个或多个字符的先前匹配的0个或1个......
      【解决方案5】:

      假设您在引号中有一个子字符串,这将提取它:

      s/."(.?)".*/$1/

      上面的答案 (s/"(.*?)"/$1/s) 只会删除引号。

      测试代码:

      my $text = "no \"need this\" again, no\n";
      my $text2 = $text;
      print $text;
      $text2 =~ s/.*\"(.*?)\".*/$1/;
      print $text2;
      $text =~ s/"(.*?)"/$1/s;
      print $text;
      

      输出:

      no "need this" again, no
      need this
      no need this again, no
      

      【讨论】:

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