3

我最近创建了一个 Perl 脚本,它使用以下代码搜索以 D 和 E 开头的单词:

$infile = 'words.txt';
open(IN, $infile);
$count = 0;
while ($word = <IN>) {
chomp($word);
if ($word =~ /^d\w*e$/i) {
    print "$word\n";
    $count++;
  }
}
print "$count\n";

我最近决定分叉代码并创建一个脚本来搜索六个字母的单词,并且单词中的字母按字母顺序(A 到 Z)。我打算使用位于usr/share/dict/words的 Unix 标准字典,而不是使用words.txt。如何通过修改此代码来完成此操作?

4

4 回答 4

9

看起来您真正需要的是一种算法,用于检查给定单词中的字母是否按字母顺序排列。有几种方法,但这个子例程通过将单词拆分为其组成字符的列表、对该列表进行排序并重新组合来工作。如果结果与原始单词匹配,则该单词已经排序。

use strict;
use warnings;

use feature 'fc';

for (qw/ a ab ba cab alt effort toffee /) {
  print "$_\n" if in_alpha_order($_);
}

sub in_alpha_order {
  my $word = fc(shift);
  my $new = join '', sort $word =~ /./g;
  return $new eq $word;
}

输出

a
ab
alt
effort

如果你真的想在正则表达式中做到这一点,你可以建立一个像

a(?=[a-z]) | b(?=[b-z]) | c(?=[c-z]) ...

这是一个以这种方式工作的程序。它的输出与上面的输出相同。

use strict;
use warnings;

my $regex = join '|', map "${_}(?=[$_-z])", 'a'..'z';
$regex = qr/^(?:$regex)*.$/i;

for (qw/ a ab ba cab alt effort toffee /) {
  print "$_\n" if $_ =~ $regex;
}
于 2013-01-07T02:28:47.270 回答
2

支持非 ASCII 字:

#!/usr/bin/perl
use strict;
use warnings;
use encoding 'utf8'; # Upgrade byte strings using UTF-8
use Unicode::Collate; # To sort letters alphabetically

use constant NCHARS => 6; # Consider only words with NCHARS characters in them
my $filename = '/usr/share/dict/words';
open (my $fh, '<:encoding(UTF-8)', $filename)
    or die "can't open '$filename' $!";

my $collator = Unicode::Collate::->new();
while (my $word = <$fh>) {
    chomp $word;
    my @chars = ($word =~ /\X/g); # Split word into characters
    # Print words with given length that have characters in alphabetical order
    print "$word\n" if (@chars == NCHARS &&
                        join('', $collator->sort(@chars)) eq $word);
}
close $fh;
于 2013-01-07T03:54:52.360 回答
1

这是一个选项:

#!/usr/bin/env perl

use warnings;
use strict;

my $wordsFile = '/usr/share/dict/words';
my $count     = 0;

open my $fh, '<', $wordsFile or die $!;

while ( my $word = <$fh> ) {
    chomp $word;
    next unless length $word == 6;

    my $sorted = join '', sort split //, lc $word;

    if ( $sorted eq lc $word ) {
        print "$word\n";
        $count++;
    }
}

close $fh;

print "$count\n";

split是按字母顺序排列字母的原始单词。这些字母被重新join编成一个新词。然后与原始单词进行比较。如果它们相同,则将其打印并计数。

于 2013-01-07T02:34:44.077 回答
1

我有一个类似于 Kenosis 和 Borodin 的解决方案,但是你需要小心大小写。Perl 的默认排序功能将所有大写字母放在小写之前。我下面的版本会处理这个问题。

#!/usr/bin/env perl

use strict;
use warnings;

sub is_six_letter_word {
    my $word = shift;
    return length($word) == 6;
}

sub is_letters_in_alphabetical_order {
    my $word = shift;
    $word = fc($word);

    my @chars = split("", $word);
    my $sorted_word = join("", sort(@chars));

    return $word eq $sorted_word;
}

open(my $fh_in, $ARGV[0]) or die "Error opening input file";

my $word = undef;
while ($word = <$fh_in>) {
    chomp($word);
    if (is_six_letter_word($word) && is_letters_in_alphabetical_order($word)) {
        printf("%s\n", $word);
    }
}

close($fh_in);
于 2013-01-07T02:51:34.480 回答