我正在寻找可能适用于此问题的模块,正则表达式或其他任何内容。
我如何以编程方式解析字符串并创建已知的英语& |西班牙语单词,我有一个字典表,我可以检查算法的随机化匹配的每个排列?
给出一组字符:EBLAIDL KDIOIDSI ADHFWB
该计划应该返回:BLADE
AID
KID
KIDS
FIDDLE
HOLA
等....
我也希望能够定义最小值和最小值。最大字长以及音节数
输入长度无关紧要,它必须只是字母,标点符号无关紧要。
感谢您的帮助
编辑
可以重复使用输入字符串中的字母。
例如,如果输入为:ABLED
,则输出可能包含:BALL
或BLEED
答案 0 :(得分:4)
你还没有指定,所以我假设输入中的每个字母只能使用一次。
[你在输入中指定的字母可以多次使用,但我会在这里留下这篇文章以防有人发现它有用。]
有效地做到这一点的关键是对单词中的字母进行排序。
abracadabra => AAAAABBCDRR
abroad => AABDOR
drab => ABDR
然后很明显“drab”在“abracadabra”中。
abracadabra => AAAAABBCDRR
drab => A B DR
那“国外”不是。
abracadabra => AAAAABBCD RR
abroad => AA B DOR
让我们将已排序的字母称为“签名”。如果您可以从“A”的签名中删除字母以获得“B”的签名,则单词“B”in在单词“A”中。使用正则表达式模式很容易检查。
sig('drab') =~ /^A?A?A?A?A?B?B?C?D?R?R?\z/
或者如果我们为了提高效率而消除不必要的回溯,我们得到
sig('drab') =~ /^A?+A?+A?+A?+A?+B?+B?+C?+D?+R?+R?+\z/
既然我们知道我们想要什么样的模式,那只需要构建它。
use strict;
use warnings;
use feature qw( say );
sub sig { join '', sort grep /^\pL\z/, split //, uc $_[0] }
my $key = shift(@ARGV);
my $pat = sig($key);
$pat =~ s/.\K/?+/sg;
my $re = qr/^(?:$pat)\z/s;
my $shortest = 9**9**9;
my $longest = 0;
my $count = 0;
while (my $word = <>) {
chomp($word);
next if !length($word); # My dictionary starts with a blank line!!
next if sig($word) !~ /$re/;
say $word;
++$count;
$shortest = length($word) if length($word) < $shortest;
$longest = length($word) if length($word) > $longest;
}
say "Words: $count";
if ($count) {
say "Shortest: $shortest";
say "Longest: $longest";
}
示例:
$ perl script.pl EBLAIDL /usr/share/dict/words
A
Abe
Abel
Al
...
libel
lid
lie
lied
Words: 117
Shortest: 1
Longest: 6
答案 1 :(得分:3)
好吧,正则表达式相当容易......然后你只需要遍历字典中的单词。 EG,假设一个标准的linux:
# perl -n -e 'print if (/^[EBLAIDL]+$/);' /usr/share/dict/words
将快速返回该文件中包含这些字词的所有单词,并且只返回那些字母。
A
AA
AAA
AAAA
AAAAAA
AAAL
AAE
AAEE
AAII
AB
...
但是,正如您所看到的,您需要一个值得的字典文件 有。特别是我的Fedora系统上的/ usr / share / dict / words 包含一堆带有所有As的单词,可能是也可能不是 你想要的东西。所以仔细选择你的字典文件。
对于最小长度,你也可以很快得到它:
$min = 9999;
$max = -1;
while(<>) {
if (/[EBLAIDL]+$/) {
print;
chomp;
if (length($_) > $max) {
$max = length($_);
$maxword = $_;
}
if (length($_) < $min) {
$min = length($_);
$minword = $_;
}
}
}
print "longest: $maxword\n";
print "shortest: $minword\n";
将产生:
ZI
ZMRI
ZWEI
longest: TANSTAAFL
shortest: A
如上文评论中所述,将单词分成碎片并计算音节是非常特定于语言的。
答案 2 :(得分:1)
我能想象的唯一方法就是解析所有可能的字母组合,并将它们与字典进行比较。将它们与字典进行比较的最快方法是将该字典转换为哈希。这样,您可以快速查找该单词是否是有效单词。
我通过对字典单词中的所有字母进行下限来键入我的字典,然后删除任何非字母字符只是为了安全起见。对于该值,我将存储实际的字典单词。例如:
cant => "can't",
google => "Google",
这样,我就可以显示拼写正确的单词。
我发现Math::Combinatorics看起来很不错,但并不像我希望的那样工作。你给它一个字母列表,它将返回你指定的字母数的所有字母组合。因此,我认为我所要做的就是将字母转换成单个字母的列表,然后简单地遍历所有可能的组合!
不......这给了我所有无序的组合。然后,我必须做的是每个组合,列出这些字母的所有可能的排列。胡说! Ptooy! Yech!
所以,循环中臭名昭着的循环。实际上,三个循环。 *外部循环简单地倒计数从1到字中字母数的所有组合数。 *下一个查找每个字母组的所有无序组合。 *最后,最后一个采用所有无序组合,并从这些组合中返回一个排列列表。
现在,我终于可以采用那些字母排列,并将其与我的词典进行比较。令人惊讶的是,程序的运行速度比我预期的要快得多,因为它必须将235,886字的字典转换为哈希值,然后循环通过三层环路来查找所有可能字母数的所有组合的所有排列。整个程序在不到两秒的时间内完成。
#! /usr/bin/env perl
#
use strict;
use warnings;
use feature qw(say);
use autodie;
use Data::Dumper;
use Math::Combinatorics;
use constant {
LETTERS => "EBLAIDL",
DICTIONARY => "/usr/share/dict/words",
};
#
# Create Dictionary Hash
#
open my $dict_fh, "<", DICTIONARY;
my %dictionary;
foreach my $word (<$dict_fh>) {
chomp $word;
(my $key = $word) =~ s/[^[:alpha:]]//;
$dictionary{lc $key} = $word;
}
#
# Now take the letters and create a Perl list of them.
#
my @letter_list = split // => LETTERS;
my %valid_word_hash;
#
# Outer Loop: This is a range from one letter combinations to the
# maximum letters combination
#
foreach my $num_of_letters (1..scalar @letter_list) {
#
# Now we generate a reference to a list of lists of all letter
# combinations of $num_of_letters long. From there, we need to
# take the Permutations of all those letters.
#
foreach my $letter_list_ref (combine($num_of_letters, @letter_list)) {
my @letter_list = @{$letter_list_ref};
# For each combination of letters $num_of_letters long,
# we now generate a permeation of all of those letter
# combinations.
#
foreach my $word_letters_ref (permute(@letter_list)) {
my $word = join "" => @{$word_letters_ref};
#
# This $word is just a possible candidate for a word.
# We now have to compare it to the words in the dictionary
# to verify it's a word
#
$word = lc $word;
if (exists $dictionary{$word}) {
my $dictionary_word = $dictionary{$word};
$valid_word_hash{$word} = $dictionary_word;
}
}
}
}
#
# I got lazy here... Just dumping out the list of actual words.
# You need to go through this list to find your longest and
# shortest words. Number of syllables? That's trickier, you could
# see if you can divide on CVC and CVVC divides where C = consonant
# and V = vowel.
#
say join "\n", sort keys %valid_word_hash;
运行此程序:
$ ./test.pl | column
a al balei bile del i lai
ab alb bali bill delia iba laid
abdiel albe ball billa dell ibad lea
abe albi balled billed della id lead
abed ale balli blad di ida leal
abel alible be blade dial ide led
abide all bea blae dib idea leda
abie alle bead d die ideal lei
able allie beal da dieb idle leila
ad allied bed dab dill ie lelia
ade b beid dae e ila li
adib ba bel dail ea ill liable
adiel bad bela dal ed l libel
ae bade beld dale el la lid
ai bae belial dali elb lab lida
aid bail bell dalle eld label lide
aide bal bella de eli labile lie
aiel bald bid deal elia lad lied
ail baldie bide deb ell lade lila
aile bale bield debi ella ladle lile
答案 3 :(得分:1)
如果你用字母表中的26个字母创建一个单独的表格,它可能会有所帮助。然后,您将构建一个查询,在第二个数据库中搜索您定义的任何字母。查询确保每个结果都是唯一的非常重要。
因此,您有一个包含您的单词的表,并且您与包含字母表的所有字母的另一个表具有多对多的关系。您将在第二个表上查询并使结果唯一。您可以对字母数量采用类似的方法。
您可以对字母和音节的数量使用相同的方法。因此,您可以创建一个可以加入所需信息的查询。在数据库上放置正确的索引以帮助提高性能,使用适当的缓存,如果是这样,您可以并行化搜索。