如何从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 以匹配问题中的示例代码,但所有处理都是使用字符串中文件内容的显示正则表达式完成的。

输出如愿(除了这里的lineworld来了两次,什么是正确的)。

请注意,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 lcmap { 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 样式应用于传入列表。
  • printprint $_的简写,在for循环中会为每个列表项打印一次。
  • perl 命令中的 -l 开关将为我们“修复”行尾(从输入中删除它们,在输出中添加它们)。这将使最后的打印效果更漂亮。

我不会说这会产生完美的结果,但您应该能够掌握一些技巧来完成您自己的程序。