Regex 如何在此特定文本上使用正则表达式捕获多个单词?
我试图从以下示例文本中提取薪酬最高的职务: 数据科学家 #在收入最高的工作中排名第一 5100个预计就业岗位250000美元工资中位数0.5%失业率 程序员 #2.从事报酬最高的工作 4000个预计就业岗位24万美元工资中位数1.0%失业率 SAP模块顾问 #3.薪水最高的工作 3000个预计工作22万美元工资中位数0.2%失业率 通过使用以下正则表达式和Perl代码Regex 如何在此特定文本上使用正则表达式捕获多个单词?,regex,perl,Regex,Perl,我试图从以下示例文本中提取薪酬最高的职务: 数据科学家 #在收入最高的工作中排名第一 5100个预计就业岗位250000美元工资中位数0.5%失业率 程序员 #2.从事报酬最高的工作 4000个预计就业岗位24万美元工资中位数1.0%失业率 SAP模块顾问 #3.薪水最高的工作 3000个预计工作22万美元工资中位数0.2%失业率 通过使用以下正则表达式和Perl代码 使用File::Glob; 本地$/=undef; 我的$file=@ARGV[0]; 打开输入,“为什么不逐行处理,简单易行
使用File::Glob;
本地$/=undef;
我的$file=@ARGV[0];
打开输入,“为什么不逐行处理,简单易行
use warnings;
use strict;
use feature 'say';
my $file = shift || die "Usage: $0 file\n";
open my $fh, '<', $file or die "Can't open $file: $!";
my (@jobs, $prev_line);
while (my $line = <$fh>) {
chomp $line;
next if not $line =~ /\S/;
if ($line =~ /^\s*#[0-9]/) {
push @jobs, $prev_line;
}
$prev_line = $line;
}
say for @jobs;
问题并不是说是否也需要排名,但regex中有一个提示,表明它们可能需要排名。然后,假设文件中的顺序是“正确”的,您可以迭代数组索引,并使用它们的索引(秩)打印元素(标题)
或者,可以肯定地说,在正则表达式中捕获它们,/^\s*#([0-9]+)/
。然后您可以直接打印标题及其排名,或者将它们存储在具有键值对的哈希中rank=>title
对于正则表达式,需要进行一些更正。要在匹配之前合成正则表达式,最好使用运算符。要处理多行字符串,需要使用/m
修饰符。(请参阅。)正则表达式本身需要修复。例如
my $regex = qr/^(.+)?(?:\n\s*)+\n\s*#\s*[0-9]/m;
my @titles = $content =~ /$regex/g
捕获一行之后至少有一个空行,然后在另一行上捕获#N
如果还需要标题的排名,那么也将其捕获,并存储在散列中
my $regex = qr/^(.+)?(?:\n\s*)+\n\s*#\s*([0-9]+)/m;
my %jobs = reverse $content =~ /$regex/g;
或者最好不要用反向推送它,而是迭代匹配列表
my %jobs;
while ($content =~ /$regex/g) {
$jobs{$2} = $1;
}
因为有了它,我们可以在每次迭代中检查我们的“捕获”,进行其他处理,等等。然后您可以按顺序对要打印的键进行排序
say "#$_ $jobs{$_}" for sort { $a <=> $b } keys %jobs;
对排序{$a$b}键%jobs说“#$$jobs{$}”;
一般来说,只要根据需要按职级选择工作就行了
我认为可以公平地说,这里的正则表达式比第一个程序复杂得多。您没有考虑空格(如Data Scientist
):
^\w+.*$\R+#(\d+)
看。
\R
等于(?>\R\n |\n |\R |\f |\x0b |\x85)
(匹配Unicode换行符序列)。回答您的问题:
您只捕获了第二个单词,并且不允许在它们之间留有空格。这就是它不匹配的原因,例如,Data Scientist
>P>使用<代码> QR///<代码>操作符编译动态内容的正则表达式。该错误源于正则表达式中的“代码> $/CODE”,Perl正则表达式编译器假定您错了,因为<代码> $>代码>应该只出现在正则表达式的结尾。
以下代码应达到您的要求。请注意两步方法:
查找匹配的文本
- 行首(
^
)
- 一个或多个由空格分隔的单词(
\w+(?:\s+\w+*
,无需捕获匹配项)
- 两行结束(
\n\n
)
#
后面跟一个数字(\d+
)
- 多次应用正则表达式(
/g
)并将字符串视为多行(/m
,即^
将匹配输入文本中某行的任何开头)
在行尾拆分匹配(\n
)并提取第一个和第三个字段
- 我们知道,
$match
将包含三行,这种方法比编写另一个正则表达式容易得多
对您在问题中提供的示例文本进行测试
$perl dummy.pl dummy.txt
匹配“数据科学家”“1”
匹配“程序员”“2”
匹配“SAP模块顾问”“3”
UNICODE更新:根据@Jan的回答,代码可以改进如下:
my$regex=qr/^(\w+(?:\s+\w+)*\R\R\d+)/m;
...
我的($title,undf,$rank)=拆分(/\R/,$match);
这可能是更通用的方法,因为UTF-8
是File::Slurper::read_text()
的默认值…Q2:使用qr/
操作符(请参阅)编译正则表达式。即my$regex=qr/^\w+(\w+)*$\n\n\n#(\d+)/;
。您也可以用这种方式组合子正则表达式,即my$regex=qr/${subre1}${subre2}${subre3}/
Q1有点不清楚。F.ex。第一个示例:是否要将数据科学家
与#1
匹配?谢谢你的回答。这是一个很好的正则表达式。但它不包含如何将正则表达式的结果集带入Perl数组,因此我不能用勾号选择它。@Romario:不用担心,很乐意帮助。谢谢你的帮助答案。我听说过qr//
,但已经完全忘记了。循环部分很好。以前从未见过或使用过使用功能qw(比如);
和使用文件::Slurper qw(read_text);
,但它们非常实用和精细。表达式内部(?:\s+\w+)*
有:
我尝试过在没有它的情况下重新登录,但它没有改变输出。这可能是打字错误吗?它做什么?请参阅:“(?:pattern)
这是用于群集,而不是捕获;它将子表达式分组,如()
,但不会像()
那样进行反向引用,也就是非捕获组(NCG)。当您需要对内容进行分组,但不捕获内容时,这对于稍微提高性能更为可取。我曾单独考虑过:
,但结果是组合?:
,现在这很有意义。谢谢。谢谢您的回答。我想将整个文本作为单个字符串处理,因为这不是一个很长的文本,我想看看我是否可以用一个正则表达式来解决它。@Romario当然,这就是我们学习的方式:)我只是想提供一个更简单的方法(原则上在生产中至关重要,并且有困难的问题:使用合适的计算方法和算法来分解它
^\w+.*$\R+#(\d+)
#!/usr/bin/perl
use strict;
use warnings;
use feature qw(say);
use File::Slurper qw(read_text);
my $input = read_text($ARGV[0])
or die "slurp: $!\n";
my $regex = qr/^(\w+(?:\s+\w+)*\n\n#\d+)/m;
foreach my $match ($input =~ /$regex/g) {
#say $match;
my($title, undef, $rank) = split("\n", $match);
$rank =~ s/^#//;
say "MATCH '${title}' '${rank}'";
}
exit 0;