捕获可选连字符正则表达式之间的单词

时间:2018-02-13 14:01:42

标签: regex perl hyphen

我跟随字符串类型,

abc - xyz
abc - pqr - xyz
abc - - xyz
abc - pqr uvw - xyz

我想从第一个字符串中检索文本xyz,从第二个字符串中检索pqr,从第三个字符串中检索``(空) pqr uvw。第二个连字符是可选的。 abc是静态字符串,它必须在那里。我试过跟随正则表达式,

/^(?:abc) - (.*)[^ -]?/

但是它给了我以下输出,

xyz
pqr - xyz
- xyz
pqr uvw - xyz

我不需要第二个字符串中的最后一部分。我正在使用perl进行脚本编写。可以通过正则表达式完成吗?

4 个答案:

答案 0 :(得分:3)

请注意(.*)部分是一个贪婪量化的点,除了换行符之外,它尽可能多地抓取任何0 +字符,直到行的末尾和[^ -]?,由于?量词( 1或0重复)而能够匹配空字符串,匹配行尾的空字符串。因此,pqr - xyz的{​​{1}}输出仅适用于正则表达式引擎。

您需要在此处使用更严格的模式。 E.g。

abc - pqr - xyz

请参阅regex demo

<强>详情

  • /^abc\h*-\h*((?:[^\s-]+(?:\h+[^\s-]+)*)?)/ - 字符串的开头
  • ^ - abc
  • abc - 用0+水平空格包围的连字符
  • \h*-\h* - 第1组捕获可选的出现次数
    • ((?:[^\s-]+(?:\h+[^\s-]+)*)?) - 除了空格和[^\s-]+
    • 之外的1个或多个字符
    • - - 零次或多次重复
      • (?:\h+[^\s-]+)* - 1+个水平空格
      • \h+ - 除了空格和[^\s-]+
      • 之外的1个或多个字符

答案 1 :(得分:1)

您可以使用^[^-]*-\s*\K[^\s-]*

以下是它的工作原理:

^       # Matches at the beginning of the line (in multiline mode)
[^-]*   # Matches every non - characters
-       # Followed by -
\s*     # Matches every spacing characters
\K      # Reset match at current position
[^\s-]* # Matches every non-spacing or - characters

Demo

更新多个包含的字词:^[^-]*-\s*\K[^\s-]*(?:\s*[^\s-]+)*

最后一部分(?:\s*[^\s-]+)*检查是否存在以空格开头的任何其他单词。

Demo

答案 2 :(得分:1)

您可以使用拆分:

$answer = (split / \- /, $t)[1];

其中$ t是文本字符串,你想要第二次分割(即[1]从0开始)。适用于除abc之外的所有内容 - - xyz,但如果分隔符是“ - ”,那么它应该在中间有2个空格不返回任何内容。如果abc - - xyz是正确的,那么你可以在分割之前完成所有工作:

$t =~ s/\- \-/-  -/;

它只是插入一个额外的空格,因此它将匹配“ - ”两次,中间没有任何内容。

答案 3 :(得分:0)

  

可以通过正则表达式完成吗?

是的,有三个简单的正则表达式:-^\s+以及\s+$

use strict;
use warnings; 
use 5.020;
use autodie;
use Data::Dumper;

open my $INFILE, '<', 'data.txt';

my @results = map {
    (undef, my $target) = split /-/, $_, 3;
    $target =~ s/^\s+//;  #remove leading spaces
    $target =~ s/\s+$//;  #remove trailing spaces
    $target;
} <$INFILE>;

close $INFILE;

say Dumper \@results;

--output:--
$VAR1 = [
          'xyz',
          'pqr',
          '',
          'pqr uvw'
        ];