捕获可选连字符正则表达式之间的单词
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 - xyz
的 pqr - 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'
];
【讨论】:
以上是关于捕获可选连字符正则表达式之间的单词的主要内容,如果未能解决你的问题,请参考以下文章