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

Posted

技术标签:

【中文标题】捕获可选连字符正则表达式之间的单词【英文标题】:Capture word between optional hyphens regex 【发布时间】:2018-07-23 22:18:49 【问题描述】:

我有以下类型的字符串,

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

【问题讨论】:

试试regex101.com/r/WoP9T9/2 @S.Kablar 请尽量不要在 cmets 等中使用外部链接回答。一个正确的答案,为什么不做一些解释,会好很多.. 完美!有用。 @S.Kablar 如果您可以添加答案和一些解释,我可以将其标记为答案。 abc 是动态的还是静态的?如果是静态的,就用/^abc\h*-\h*(\S+)/ ^[^-]+-\s\K[^-\s]* 呢? 【参考方案1】:

请注意,(.*) 部分是一个贪婪量化的点,它尽可能多地抓取除换行符之外的任何 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 个或多个字符

【讨论】:

@Abhishek 那么^abc\h*-\h*([^-\n]*[^-\s])呢? 它可以工作,但也需要考虑\n。我只需要处理空格,而不是换行。 @Abhishek 现在不应该。并且它仍然可以在第 1 组中返回一个空值。 是的.. 谢谢!【参考方案2】:

你可以使用^[^-]*-\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

【讨论】:

相应地编辑了我的答案。 谢谢.. 但是更新了一个,也考虑了 \n 。我只需要处理空格,而不是换行。 您是否按照@wiktor 的建议尝试了水平间距?【参考方案3】:

你可以使用拆分:

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

其中 $t 是文本字符串,您希望进行第二次拆分(即 [1] 从 0 开始)。适用于除 abc - - xyz 之外的所有内容,但如果分隔符为“ - ”,则中间应有 2 个空格以不返回任何内容。如果 abc - - xyz 是正确的,那么您可以在拆分之前执行此操作以供所有人使用:

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

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

以上是关于捕获可选连字符正则表达式之间的单词的主要内容,如果未能解决你的问题,请参考以下文章

在正则表达式的可选部分中捕获的组

带有字母、数字、任意顺序的可选特殊字符的正则表达式单词

匹配正则表达式中的可选斜杠

c#正则表达式捕获两个字符串之间的字符串[重复]

正则表达式

正则表达式捕获两个数字之间的第一个字符串