【问题标题】:Regular Expression .*? and .* [duplicate]正则表达式 。*?和 .* [重复]
【发布时间】:2016-07-22 01:13:41
【问题描述】:

这两个正则表达式的作用是什么?

/<(.*?)>.*?<\/\1>/

/<(.*?)>.*<\/\1>/

我了解到.*? 意味着尽可能少的字符。

例如:

  my $a = '"helllo"++"world"';

  print "a $1\n" if $a =~/(".*")/;            # "helllo"++"world"

  print "b $1\n" if $a =~/(".*?")/;           # "helllo"

  print "c $1\n" if $a =~/(.*)/;              # "helllo"++"world"

  print "d $1\n" if $a =~/(.*?)/;             # (nothing)

为什么 d 什么也不显示,而 b 是 helllo 而不是 ""

所以,我找不到任何好的例子来展示 1 and 2 之间的区别,比如 helllo world 例子。

有人可以举一些例子来说明区别吗?

谢谢。

【问题讨论】:

  • 这意味着 - 有人试图使用正则表达式解析 XML 或 HTML,这是个坏主意。

标签: regex perl


【解决方案1】:

* 表示匹配零次或多次

*? 表示匹配零次或多次但不贪心

. 表示匹配除换行以外的任何字符

'"helllo"++"world"'这是你的搅拌器

在下面的示例中,^ 表示当前位置(字符串中有当前位置,模式中有当前位置(种类))

在你的第一种情况下。

第一步

"helllo"++"world"      ".+"
^                      ^  

第二步

"helllo"++"world"      ".+"
 ^                      ^  

第三步

"helllo"++"world"      ".+"
                ^        ^

第四步

由于我们在字符串.+ 的末尾找到",因此回溯并匹配" 之前的字符

查看"

We have the match at this position so success

"helllo"++"world"      ".+"
               ^          ^

在你的第二种情况下。 *? Match zero or more times but not greedy

第一步

  "helllo"++"world"     ".*?"
  ^                     ^  

第二步

  "helllo"++"world"     ".*?"
   ^                     ^  

第三步

  "helllo"++"world"     ".*?"
         ^                 ^  

Step4 (* 在第一个匹配满足时变为失败。)

  "helllo"++"world"     ".*?"
         ^                  ^  

在你的第三种情况下

第一步

"helllo"++"world"        .* 
^                        ^ 

第 2 步(* 是贪婪的,所以它会一直运行到结束。结果是给出所有匹配的模式)

"helllo"++"world"        .* 
                ^         ^ 

在你的第四个案例中,

你的模式是.*?这意味着任何东西(.)或更多次(*)但不是贪婪(?)。这里非贪心字符匹配零字符,所以结果为空。

【讨论】:

  • 很好的解释...
【解决方案2】:

你真的有两个问题,在这里;

这两个正则表达式的作用是什么?

/.*?\1>/

一个点,'.',是一个匹配任何字符的原子。它后面的星号表示“尽可能多地匹配前一个原子”。这种组合被称为“贪婪”,因为点匹配任何东西,而“*”表示 - “继续前进”,因此,在没有任何其他约束或锚点的情况下,组合“吃”或匹配字符串的其余部分。问号将这种行为从“贪婪”更改为“吝啬” - 它会尝试尽可能少地匹配。

圆括号 - 或括号 - 没有规定要匹配的内容 - 它们表示您想要“捕获”与第一对括号“$2”的特殊变量“$1”匹配的任何内容" 以此类推。

所以,-&lt;(.*?)&gt; 的意思是,匹配一个开尖括号(或“小于”),然后匹配任何东西(但占用尽可能少),然后匹配一个闭合角(或“大于”) .圆括号没有规定要匹配的内容 - 它们只是表示“将尖括号之间的任何文本放入 $1。”

最后一部分中的\1 &lt;\/\1&gt; 是所谓的反向引用——它的意思是“无论你在第一组圆括号中捕获的内容,我都想在这里再次匹配”。 \/ 在它之前是一个转义的正斜杠 - 所以我们在这里寻找的是一个“标签”(被尖括号包围的文本),一些文本,然后是一个匹配的“结束标签” - 即尖括号中的相同文本前面有一个“/”。

/.*\1>/

除了尝试在开始标签和结束标签之间使用尽可能多的文本之外,这几乎做同样的事情。

my $a = '"helllo"++"world"';
...
print "b $1\n" if $a =~/(".*?")/;            # "helllo"
...
print "d $1\n" if $a =~/(.*?)/;

为什么 d 什么也不显示,而 b 是“hello”而不是“”?

对于 (b),您说的是“我坚持在开头使用双引号 ("),然后是任何文本,然后我再次坚持使用双引号 (")”。现在,如果您查看 $a 中的文本,您可以看到以下所有内容都以 (") 开头和结尾,中间有一些文本;

"helllo" 
"helllo"++" 
"helllo"++"world"

这里是重点——.*?(吝啬)意味着“我想要最小的”——即在这种情况下是第一个,而.*(没有'?'——贪婪)意味着“我想要最长的" - 即在这种情况下,最后一个。

使用 (d),您在字符串的开头或结尾没有规定尖括号或双引号字符 - 您只是说“匹配任何内容,(.*),但尽可能少用”。所以,RE 什么也没给你,因为那肯定是满足条件的最小匹配项(即没有条件!:-)

【讨论】:

    【解决方案3】:

    .*? 将使用尽可能少的字符搜索匹配项。如果您将".*?""a" "b" 匹配,则正则表达式引擎将仅报告"a" 作为匹配项。贪婪版本".*" 会将整个字符串报告为匹配项,因为* 想要消耗尽可能多的输入。

    正则表达式 .*? 可以满足一个空字符串,所以如果你没有在它周围放置任何东西来防止匹配,这正是它会做的事情(就像你的情况 d)。

    您的正则表达式 1) 和 2) 用于解析看起来像 XML 的文本。考虑这段文字:

    <tag>text</tag> <tag>more text</tag>
    

    正则表达式 1) 将仅使用第一个标记的子字符串 &lt;tag&gt;text&lt;/tag&gt;,而正则表达式 2 将使用整个字符串。

    现在考虑这个文本:

    <tag>what about <tag>nested</tag> tags?</tag>
    

    正则表达式 1) 只会在第一次关闭 &lt;/tag&gt; 之前产生匹配,而正则表达式 2) 会消耗整个字符串。

    【讨论】:

      【解决方案4】:

      d) 不打印的原因非常简单:您已经知道.*? 匹配越少越好,因此如果不添加任何其他条件,“越少越好”根本不算什么。

      原因 b) "(.*?)" 匹配 "hello" 是表达式中的两个引号 - 即匹配项(如果找到)必须以引号开头和结尾。中间部分.*? 尽量少匹配,所以就是“hello”。

      【讨论】:

        猜你喜欢
        • 2016-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-11
        相关资源
        最近更新 更多