Regex 如何在Perl中从一行中提取非空白组?

Regex 如何在Perl中从一行中提取非空白组?,regex,perl,Regex,Perl,我正在编写一个程序,它必须从文件中获取值。在文件中,每行表示一个实体。每个实体有三个值。例如: 值1值2值3 我有一个常规表达式来匹配它们 m/(.*?) (.*?) (.*?)/m; 但是,似乎第三个值永远不匹配!匹配第三个值的唯一方法是在文件中添加另一个值,在表达式中添加另一个“匹配括号”。但这并不能让我满意。在考虑使用regex之前,先想想是否可以简单地解决这个问题。如果您想要获得实体,一种更简单的方法是将它们拆分。返回列表的元素将是您想要的 @s = split /\s+/ , $li

我正在编写一个程序,它必须从文件中获取值。在文件中,每行表示一个实体。每个实体有三个值。例如:

值1值2值3

我有一个常规表达式来匹配它们

m/(.*?) (.*?) (.*?)/m;

但是,似乎第三个值永远不匹配!匹配第三个值的唯一方法是在文件中添加另一个值,在表达式中添加另一个“匹配括号”。但这并不能让我满意。

在考虑使用regex之前,先想想是否可以简单地解决这个问题。如果您想要获得实体,一种更简单的方法是将它们拆分。返回列表的元素将是您想要的

@s = split /\s+/ , $line;

在考虑使用regex之前,先考虑一下是否可以简单地解决这个问题。如果您想要获得实体,一种更简单的方法是将它们拆分。返回列表的元素将是您想要的

@s = split /\s+/ , $line;

regex
末尾添加
$
以解决此问题:

m/(.*?) (.*?) (.*?)$/m;
或者,您可以使最后一部分
贪婪

m/(.*?) (.*?) (.*)/m;

regex
末尾添加
$
以解决此问题:

m/(.*?) (.*?) (.*?)$/m;
或者,您可以使最后一部分
贪婪

m/(.*?) (.*?) (.*)/m;
发生什么事? 让我们暂时简化正则表达式的捕获,因为它对发生的事情不负责任。因此,您的正则表达式如下所示:

 /.*? .*? .*?/
*?
的意思是“匹配任何字符(换行除外),无到多次,尽可能少。”

在此上下文中,第一个
*?
将尝试匹配字符串中的零个字符,然后在下一个regex元素空格上失败。它将再次尝试匹配1,2。。。字符,并将在下一个字符为实际空格时首先成功

换句话说,我们在
*?
组后面有一个空格,使它与您想要的匹配。否则它将很高兴地停止匹配零个字符

这正是你第三场比赛的情况。因为您的正则表达式在这里结束,所以空匹配确实满足正则表达式组,并且是首选匹配

避免它的方法 正如其他答案所说,可能的解决方案包括:

  • split
    (预期语义的最佳转录)
  • 使最后一次捕获贪婪(
    *
    而不是
    *?
  • 添加超过上次捕获的内容(匹配的任何内容)<代码>$如果行结束于此
  • 匹配非空格(
    \S
    )而不是任何字符(
    )。这将适用于贪婪(
    \S*
    )或非贪婪(
    \S*?
    )匹配
发生了什么事 让我们暂时简化正则表达式的捕获,因为它对发生的事情不负责任。因此,您的正则表达式如下所示:

 /.*? .*? .*?/
*?
的意思是“匹配任何字符(换行除外),无到多次,尽可能少。”

在此上下文中,第一个
*?
将尝试匹配字符串中的零个字符,然后在下一个regex元素空格上失败。它将再次尝试匹配1,2。。。字符,并将在下一个字符为实际空格时首先成功

换句话说,我们在
*?
组后面有一个空格,使它与您想要的匹配。否则它将很高兴地停止匹配零个字符

这正是你第三场比赛的情况。因为您的正则表达式在这里结束,所以空匹配确实满足正则表达式组,并且是首选匹配

避免它的方法 正如其他答案所说,可能的解决方案包括:

  • split
    (预期语义的最佳转录)
  • 使最后一次捕获贪婪(
    *
    而不是
    *?
  • 添加超过上次捕获的内容(匹配的任何内容)<代码>$如果行结束于此
  • 匹配非空格(
    \S
    )而不是任何字符(
    )。这将适用于贪婪(
    \S*
    )或非贪婪(
    \S*?
    )匹配

在这种情况下,您不想使用
*
量词,也不想让这些量词变得贪婪。正则表达式中的技巧是尽可能详细地描述模式

要匹配的行有:

  • 一些非空格
  • 一些空白
  • 再重复两次
  • 一旦描述了情况,就可以将其转换为正则表达式。您可以从描述的直译开始:

     my @values = /(\S+) (\S+) (\S+)/;
    
    由于您使用了
    \S
    ,因此捕获中的模式部分无法通过空格来匹配超出您预期的内容,就像
    *
    一样

    你已经重复了部分模式,所以你可以压缩它。由于您只是捕获一组空白,请将其改为全局匹配:

     my @values = /(\S+)/g;
    
    你也可以考虑反过来。您可以使用以下方法丢弃空白,而不是捕获非空白:


    在这种情况下,您并不想使用
    *
    量词,也不想让这些量词变得贪婪。正则表达式中的技巧是尽可能详细地描述模式

    要匹配的行有:

  • 一些非空格
  • 一些空白
  • 再重复两次
  • 一旦描述了情况,就可以将其转换为正则表达式。您可以从描述的直译开始:

     my @values = /(\S+) (\S+) (\S+)/;
    
    由于您使用了
    \S
    ,因此捕获中的模式部分无法通过空格来匹配超出您预期的内容,就像
    *
    一样

    你已经重复了部分模式,所以你可以压缩它。因为您只是捕获一组空白,所以将其设置为全局matc