如何从perl中的字符串中提取2个以上的字符词
How to extract 2+ character words from string in perl
我假设可以使用某种正则表达式来完成此操作?
我需要获取每个单词由2个或多个字符组成,以字母开头,其余字符由字母、数字和下划线组成。
这是我目前拥有的代码,虽然它与我想要的输出不太接近:
while (my $line=<>) {
# remove leading and trailing whitespace
$line =~ s/^\s+|\s+$//g;
$line = lc $line;
@array = split / /, $line;
foreach my $a (@array){
$a =~ s/[$#@~!&*()\[\];.,:?^ `\\/]+//g;
push(@list, "$a");
}
}
示例输入为:
#!/usr/bin/perl -w
use strict;
# This line will print a hello world line.
print "Hello world!\n";
exit 0;
所需的输出将是(按字母顺序排列):
bin
exit
hello
hello
line
perl
print
print
strict
this
use
usr
will
world
my @matches = $string =~ /\b([a-z][a-z0-9_]+)/ig;
如果case-insensitive操作只需要应用于子模式,可以embed it
/... \b((?i)[a-z][a-z0-9_]+) .../
(或者,子模式后可以关闭,(?i)pattern(?-i)
)
[a-zA-Z0-9_]
变成了 \w
,一个“word character”,如果这确实是所需要的。
上面的正则表达式根据需要选择单词,而不需要先在 space 上拆分行,在显示的程序中完成。可以将它应用于整行(或与此相关的整个文本),也许在所示的各种特殊字符剥离之后。†
还有一些其他情况的问题 -- 连字符怎么样?撇号?代字号?这些在标识符中找不到,虽然这似乎是为了处理编程文本,但包括注释;还有哪些其他合法字符?
注意 split-ing 白色space
显示的 split / /, $line
恰好在那个 space 上分裂。更好的是 split /\s+/, $line
—— 或者,更好的是使用 split
的特殊模式 split ' ', $line
:拆分任意数量的任意连续白色 space,以及前导和尾随spaces 被丢弃。
† 所示示例仅由给定的正则表达式按要求正确处理
use strict;
use warnings;
use feature 'say';
use Path::Tiny qw(path); # convenience, to slurp the file
my $fn = shift // die "Usage: [=12=] filename\n";
my @matches = sort map { lc }
path($fn)->slurp =~ /\b([a-z][a-z0-9_]+)/ig;
say for @matches;
我加入了排序和 lower-casing 以匹配问题中的示例代码,但所有处理都是使用字符串中文件内容的显示正则表达式完成的。
输出如愿(除了这里的line
和world
来了两次,什么是正确的)。
请注意,lc
可以应用于带有文件内容的字符串,然后用正则表达式处理,效率更高。虽然在这种情况下这在原则上是不一样的,但它可能是
perl -MPath::Tiny -wE'$f = shift // die "Need filename\n";
@m = sort lc(path($f)->slurp) =~ /\b([a-z]\w+)/ig;
say for @m'
这里我其实用的是\w
。如果不同,请调整为要匹配的实际字符。
奇怪的是,这可以用那些又长又典型的 Perl 之一来完成 one-liners
$ perl -lwe'print for sort grep /^\pL/ && length > 1, map { split /\W+/ } map lc, <>' a.txt
bin
exit
hello
hello
line
line
perl
print
print
strict
this
use
usr
will
world
world
让我们仔细研究一下,看看我们能学到什么。此行从右到左阅读。
a.txt
是要读取的参数文件
<>
是菱形运算符,从文件中读取行。由于这是列表上下文,它将耗尽文件句柄和 return 所有行。
map lc
,map { lc($_) }
的缩写,将在所有行上应用 lc
函数,并 return 结果。
map { split /\W+/ }
是一个 multi-purpose 操作。它将删除不需要的字符(non-word 字符),并在那里拆分行,return 所有这些单词的列表。
grep /^\pL/ && length > 1
对以字母 \pL
开头且长度超过 1 的字符串进行排序 return。
sort
按字母顺序对从右进入的列表进行排序,return 从左进入
for
是 for-loop,以 post-fix 样式应用于传入列表。
print
是print $_
的简写,在for循环中会为每个列表项打印一次。
- perl 命令中的
-l
开关将为我们“修复”行尾(从输入中删除它们,在输出中添加它们)。这将使最后的打印效果更漂亮。
我不会说这会产生完美的结果,但您应该能够掌握一些技巧来完成您自己的程序。
我假设可以使用某种正则表达式来完成此操作?
我需要获取每个单词由2个或多个字符组成,以字母开头,其余字符由字母、数字和下划线组成。
这是我目前拥有的代码,虽然它与我想要的输出不太接近:
while (my $line=<>) {
# remove leading and trailing whitespace
$line =~ s/^\s+|\s+$//g;
$line = lc $line;
@array = split / /, $line;
foreach my $a (@array){
$a =~ s/[$#@~!&*()\[\];.,:?^ `\\/]+//g;
push(@list, "$a");
}
}
示例输入为:
#!/usr/bin/perl -w
use strict;
# This line will print a hello world line.
print "Hello world!\n";
exit 0;
所需的输出将是(按字母顺序排列):
bin
exit
hello
hello
line
perl
print
print
strict
this
use
usr
will
world
my @matches = $string =~ /\b([a-z][a-z0-9_]+)/ig;
如果case-insensitive操作只需要应用于子模式,可以embed it
/... \b((?i)[a-z][a-z0-9_]+) .../
(或者,子模式后可以关闭,(?i)pattern(?-i)
)
[a-zA-Z0-9_]
变成了 \w
,一个“word character”,如果这确实是所需要的。
上面的正则表达式根据需要选择单词,而不需要先在 space 上拆分行,在显示的程序中完成。可以将它应用于整行(或与此相关的整个文本),也许在所示的各种特殊字符剥离之后。†
还有一些其他情况的问题 -- 连字符怎么样?撇号?代字号?这些在标识符中找不到,虽然这似乎是为了处理编程文本,但包括注释;还有哪些其他合法字符?
注意 split-ing 白色space
显示的 split / /, $line
恰好在那个 space 上分裂。更好的是 split /\s+/, $line
—— 或者,更好的是使用 split
的特殊模式 split ' ', $line
:拆分任意数量的任意连续白色 space,以及前导和尾随spaces 被丢弃。
† 所示示例仅由给定的正则表达式按要求正确处理
use strict;
use warnings;
use feature 'say';
use Path::Tiny qw(path); # convenience, to slurp the file
my $fn = shift // die "Usage: [=12=] filename\n";
my @matches = sort map { lc }
path($fn)->slurp =~ /\b([a-z][a-z0-9_]+)/ig;
say for @matches;
我加入了排序和 lower-casing 以匹配问题中的示例代码,但所有处理都是使用字符串中文件内容的显示正则表达式完成的。
输出如愿(除了这里的line
和world
来了两次,什么是正确的)。
请注意,lc
可以应用于带有文件内容的字符串,然后用正则表达式处理,效率更高。虽然在这种情况下这在原则上是不一样的,但它可能是
perl -MPath::Tiny -wE'$f = shift // die "Need filename\n";
@m = sort lc(path($f)->slurp) =~ /\b([a-z]\w+)/ig;
say for @m'
这里我其实用的是\w
。如果不同,请调整为要匹配的实际字符。
奇怪的是,这可以用那些又长又典型的 Perl 之一来完成 one-liners
$ perl -lwe'print for sort grep /^\pL/ && length > 1, map { split /\W+/ } map lc, <>' a.txt
bin
exit
hello
hello
line
line
perl
print
print
strict
this
use
usr
will
world
world
让我们仔细研究一下,看看我们能学到什么。此行从右到左阅读。
a.txt
是要读取的参数文件<>
是菱形运算符,从文件中读取行。由于这是列表上下文,它将耗尽文件句柄和 return 所有行。map lc
,map { lc($_) }
的缩写,将在所有行上应用lc
函数,并 return 结果。map { split /\W+/ }
是一个 multi-purpose 操作。它将删除不需要的字符(non-word 字符),并在那里拆分行,return 所有这些单词的列表。grep /^\pL/ && length > 1
对以字母\pL
开头且长度超过 1 的字符串进行排序 return。sort
按字母顺序对从右进入的列表进行排序,return 从左进入for
是 for-loop,以 post-fix 样式应用于传入列表。print
是print $_
的简写,在for循环中会为每个列表项打印一次。- perl 命令中的
-l
开关将为我们“修复”行尾(从输入中删除它们,在输出中添加它们)。这将使最后的打印效果更漂亮。
我不会说这会产生完美的结果,但您应该能够掌握一些技巧来完成您自己的程序。