Как я могу создать список слов из группы букв, используя Perl? - PullRequest
4 голосов
/ 02 февраля 2012

Я искал модуль, регулярное выражение или что-то еще, что может относиться к этой проблеме.

Как я могу программно разобрать строку и создать известный английский & | Испанские слова, учитывая, что у меня есть словарная таблица, по которой я могу проверить каждую перестановку рандомизации алгоритма на совпадение?

Дана группа символов: EBLAIDL KDIOIDSI ADHFWB

Программа должна вернуть: BLADE AID KID KIDS FIDDLE HOLA и т.д ....

Я также хочу иметь возможность определить минимальную и максимальную длину слова, а также количество слогов

Длина ввода не имеет значения, это должны быть только буквы, а пунктуация не имеет значения.

Спасибо за любую помощь

РЕДАКТИРОВАТЬ
Буквы во входной строке можно использовать повторно.

Например, если ввод: ABLED, то вывод может содержать: BALL или BLEED

Ответы [ 4 ]

4 голосов
/ 02 февраля 2012

Вы не указали, поэтому я предполагаю, что каждая буква во входных данных может быть использована только один раз.

[Вы указали, что указанные буквы во входных данных могут использоваться более одного раза, но я собираюсь оставить этот пост здесь на случай, если кто-то посчитает его полезным.]

Ключом к эффективному выполнению этой задачи является сортировка букв в словах.

abracadabra => AAAAABBCDRR
abroad      => AABDOR
drab        => ABDR

Тогда становится ясно, что "серость" есть в "абракадабре".

abracadabra => AAAAABBCDRR
drab        => A    B  DR

А это «за границей» не так.

abracadabra => AAAAABBCD RR
abroad      => AA   B  DOR

Давайте назовем отсортированное письмо «подписью». Слово «B» находится в слове «A», если вы можете удалить буквы из подписи «A», чтобы получить подпись «B». Это легко проверить с помощью шаблона регулярных выражений.

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";
}
* * 1 022 Пример: * 1 023 *
$ perl script.pl EBLAIDL /usr/share/dict/words
A
Abe
Abel
Al
...
libel
lid
lie
lied

Words:    117
Shortest: 1
Longest:  6
3 голосов
/ 02 февраля 2012

Ну, регулярное выражение довольно просто ... Тогда вам просто нужно перебрать слова в словаре. Например, в стандартном Linux:

# perl -n -e 'print if (/^[EBLAIDL]+$/);' /usr/share/dict/words

Быстро вернет все слова в этом файле, содержащие эти и только эти буквы.

A
AA
AAA
AAAA
AAAAAA
AAAL
AAE
AAEE
AAII
AB
...

Как видите, вам нужен файл словаря, который стоит иметь. В частности, / usr / share / dict / words в моей системе Fedora содержит кучу слов со всеми, которые могут или не могут быть то, что вы хотите. Поэтому тщательно подбирайте файл словаря.

Для минимальной максимальной длины вы также можете быстро получить это:

$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

Для разбиения слов на части и подсчета слогов очень специфичен язык, как уже упоминалось в комментариях выше.

1 голос
/ 04 февраля 2012

Может быть, это поможет, если вы создадите отдельную таблицу с 26 буквами алфавита. Тогда вы создадите запрос, который будет искать во второй базе данных любую букву, которую вы определили. Важно, чтобы запрос гарантировал, что каждый результат уникален.

Итак, у вас есть таблица, содержащая ваши слова, и у вас есть отношение многих ко многим к другой таблице, которая содержит все буквы алфавитов. И вы бы запросили эту вторую таблицу и сделали результаты уникальными. Вы могли бы иметь подобный подход к количеству букв.

Вы можете использовать тот же подход для количества букв и слогов. Таким образом, вы сделаете один запрос, который объединит всю информацию, которую вы хотите. Поместите правильные индексы в базу данных, чтобы повысить производительность, использовать соответствующее кэширование, и, если это необходимо, вы можете распараллеливать поиски.

1 голос
/ 02 февраля 2012

Единственный способ представить, как это сработает, - это проанализировать все возможные комбинации букв и сравнить их со словарем. Самый быстрый способ сравнить их со словарем - это превратить этот словарь в хеш. Таким образом, вы можете быстро узнать, было ли это слово верным.

Я набираю в своем словаре нижний регистр всех букв в словарном слове, а затем удаляю все не-буквенные символы, чтобы быть в безопасности. Для значения я буду хранить фактическое слово словаря. Например:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...