Вопрос или проблема
Я хотел бы написать скрипт для поиска по /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";
}
Как работает скрипт
- Чтение слов: Скрипт читает слова из стандартного ввода. Для этого можно передать файл словаря в качестве аргумента командной строки.
- Проверка палиндромов: Каждое слово проверяется на предмет того, является ли оно палиндромом, и если да, то выводится на экран.
- Поиск обратимых слов: Скрипт проверяет каждое слово и сравнивает его первую и вторую половины, чтобы определить, формируют ли они вместе другое слово, которое существует в словаре.
Альтернативные инструменты
Хотя 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 и другие языки также могут быть эффективны. Однако наилучший результат достигается при правильном понимании поставленных задач и доступных инструментов. Используйте приведённые примеры как основу и адаптируйте их под ваши задачи, изменяя критерии поиска.