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

Capture word between optional hyphens regex

我有以下类型的字符串,

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 编写脚本。可以通过正则表达式完成吗?

请注意,(.*) 部分是一个贪婪量化的点,它会抓取除换行符以外的任何 0+ 个字符,尽可能多,直到行尾和 [^ -]? , 由于 ? 量词(1 或 0 次重复),能够匹配空字符串,匹配行尾的空字符串。因此,abc - pqr - xyzpqr - xyz 输出仅对正则表达式引擎是合乎逻辑的。

您需要在此处使用限制性更强的模式。例如

/^abc\h*-\h*((?:[^\s-]+(?:\h+[^\s-]+)*)?)/

参见regex demo

详情

  • ^ - 字符串的开头
  • abc - 一个 abc
  • \h*-\h* - 用 0+ 个水平空格包围的连字符
  • ((?:[^\s-]+(?:\h+[^\s-]+)*)?) - 第 1 组捕获可选的出现
    • [^\s-]+ - 除了空格和 -
    • 之外的 1 个或更多字符
    • (?:\h+[^\s-]+)* - 零次或多次重复
      • \h+ - 1+ 水平空格
      • [^\s-]+ - 除了空格和 -
      • 之外的 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-]+)* 检查是否存在以 space(s) 开头的任何其他单词。

Demo

Can it be done via regex?

是的,使用三个简单的正则表达式:-^\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'
        ];

你可以使用拆分:

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

其中 $t 是文本字符串,您想要第二次拆分(即 [1] 从 0 开始)。适用于除 abc - - xyz 之外的所有内容,但如果分隔符是“-”,则中间应该有 2 spaces 到 return 什么都没有。如果 abc - - xyz 是正确的,那么您可以在拆分之前执行此操作以使所有工作正常:

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

它只是插入一个额外的 space,所以它会匹配“-”两次,中间没有任何内容。