Поиск в /usr/dict/words для нахождения слов с определёнными свойствами

Вопрос или проблема

Я хотел бы написать скрипт для поиска по /usr/dict/words, чтобы найти все слова, которые соответствуют некоторым заданным критериям. Например, найти все палиндромные слова (такие как “racecar”, “madam” и т. д.) или найти все слова, в которых первая и вторая половины, развернутые, также образуют слово (например, “german” и “manger”). Основой скрипта будет простой цикл для чтения каждого слова в словаре, и я смогу изменить критерии в зависимости от того, что хочу искать, подставив выражение или что-то похожее.

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

Какой инструмент(ы) будет лучше всего использовать для этой задачи?

Следующий perl скрипт считывает список слов из stdin и/или из имен файлов, указанных на командной строке, и выводит все найденные палиндромы и обратимые слова. Он игнорирует слова длиной менее 3 символов (в основном потому, что мой файл /usr/share/dict/words содержит много такого мусора, как ‘A’ и ‘Aa’).

Это написано на чрезвычайно простом perl, предназначенном для того, чтобы его было легко понять и модифицировать, без использования каких-либо ‘умных’ трюков perl.

#! /usr/bin/perl

use strict;

my %dict = ();

print "Палиндромы\n";
print "-----------\n";

while(<>) {
   chomp;
   next if (length($_) < 3);

   $dict{$_} = 1;
   print "$_\n" if ($_ eq reverse($_));
}


print "\n\nОбратимые слова\n";
print "-----------\n";
foreach my $key (keys %dict) {

    my $len = length($key);
    my $firsthalf="";
    my $secondhalf="";

    if (($len / 2) == int($len/2)) {
        # слова четной длины
        $firsthalf = substr($key,0,int($len/2));
        $secondhalf = substr($key,int($len/2));
    } else {
        # слова нечетной длины
        $firsthalf = substr($key,0,int($len/2)+1);
        $secondhalf = substr($key,int($len/2)+1);
    };

    my $rev = $secondhalf . $firsthalf;

    next unless (exists $dict{$rev});

    # не печатать, если обратное слово - палиндром
    next if ($rev eq $key);

    print  "$key => $rev\n";
}

Выводит такой результат:

$ ./find-P-and-R.pl /usr/share/dict/words
Палиндромы
-----------
MGM
aba
abba
aga
aha
aia
aka
...
...
...


Обратимые слова
-----------
mode => demo
reenter => terreen
juba => baju
oon => noo
lave => vela
lassi => silas
updo => doup
air => rai
...
...
...

Если вам нужно только фильтровать регулярные выражения, используйте grep. Но то, что вы хотите, выходит за рамки регулярных выражений. Вы можете использовать любой язык программирования, с которым вам удобно работать. Awk присутствует на всех системах POSIX и может легко обрабатывать файлы строчка за строчкой, но его программные возможности не на высшем уровне. Perl упрощает обработку построчно и имеет лучшие средства обработки строк, а также много доступных библиотек. Python легко выучить и имеет очень хороший набор доступных библиотек. Существует много других возможностей.

Чтобы проверить на палиндромы, на *BSD и Linux вы можете использовать rev утилиту в конвейере. Она разворачивает каждую строку файла. Чтобы найти палиндромы:

rev /usr/dict/words | paste /usr/dict/words - | sed -n 's/^\(.*\)\t\1$/\1/p'
perl -l -ne 'print if reverse($_) eq $_' /usr/dict/words

Чтобы найти обратимые слова:

rev /usr/dict/words | grep -Fxf /usr/dict/words
perl -l -ne '$dict{$_} = 1; END {foreach (keys %dict) {print if $dict{reverse($_)}}}'

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

Пример 1: найти слова-палиндромы длиной 3 буквы в словаре со “o” в середине

  $ sed -E -n '/^(.)o\1$/p' /usr/share/dict/words
  bob
  mom
  non
  pop
  sos
  tot
  wow

Пример 2: найти слова-палиндромы длиной 6 букв

  $ sed -E -n '/^(.)(.)(.)\3\2\1$/p' /usr/share/dict/words
  redder

Ответ или решение

Поиск слов с определёнными свойствами в файле /usr/dict/words

Вопрос о том, как написать скрипт для поиска слов в словаре /usr/dict/words, который будет соответствовать определённым критериям, является интересной задачей в области обработки текстов. Например, можно искать палиндромы (слова, которые читаются одинаково слева направо и справа налево, как "racecar" или "madam") или слова, которые при перевороте первой и второй половин образуют другое слово (например, "german" и "manger").

Структура скрипта

Для реализации данной задачи можно использовать любой современный язык программирования, но в качестве примера мы рассмотрим язык Perl. Отметим, что данный язык предоставляет простые средства для работы со строками и регулярными выражениями, что делает его идеальным выбором.

Вот пример простого Perl-скрипта, который выполняет заданные функции:

#! /usr/bin/perl

use strict;

my %dict = ();

print "Палиндромы\n";
print "-----------\n";

while (<>) {
   chomp;
   next if (length($_) < 3);

   $dict{$_} = 1;
   print "$_\n" if ($_ eq reverse($_));
}

print "\n\nОбратимые слова\n";
print "-----------\n";
foreach my $key (keys %dict) {

    my $len = length($key);
    my $firsthalf="";
    my $secondhalf="";

    if (($len / 2) == int($len/2)) {
        # Слово четной длины
        $firsthalf = substr($key,0,int($len/2));
        $secondhalf = substr($key,int($len/2));
    } else {
        # Слово нечетной длины
        $firsthalf = substr($key,0,int($len/2)+1);
        $secondhalf = substr($key,int($len/2)+1);
    };

    my $rev = $secondhalf . $firsthalf;

    next unless (exists $dict{$rev});

    # Избежать печати палиндромов
    next if ($rev eq $key);

    print  "$key => $rev\n";
}

Как работает скрипт

  1. Чтение слов: Скрипт читает слова из стандартного ввода. Для этого можно передать файл словаря в качестве аргумента командной строки.
  2. Проверка палиндромов: Каждое слово проверяется на предмет того, является ли оно палиндромом, и если да, то выводится на экран.
  3. Поиск обратимых слов: Скрипт проверяет каждое слово и сравнивает его первую и вторую половины, чтобы определить, формируют ли они вместе другое слово, которое существует в словаре.

Альтернативные инструменты

Хотя Perl — отличный выбор для данной задачи, вы также можете рассмотреть другие языки программирования:

  • Python: Легко изучать, имеет хорошую поддержку обработки строк и множество библиотек.
  • AWK: Подходит для простых задач, но его возможности по обработке строк ограничены.
  • Sed: Можно использовать для фильтрации по регулярным выражениям, хотя работа с текстом будет менее удобной, чем в Perl или Python.

Альтернативные подходы с использованием командной строки

Для простых случаев, таких как нахождение палиндромов, можно использовать комбинацию стандартных утилит Unix. Например, это можно сделать с помощью rev и sed:

rev /usr/dict/words | paste /usr/dict/words - | sed -n 's/^\(.*\)\t\1$/\1/p'

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...