Этот сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Англо-русский словарь на bc

Пока писал «Виселицу» на bc, в процессе немало с ним экспериментировал. Обратил внимание на то, какой он шустрый. Я не делал прямых сравнений, но сложилось такое впечатление. Подмывало как-то потестировать скорость поплотнее, но забил.

Позже, не справившись с исследовательским зудом, решил попробовать сделать на нём что-то нарочито многострочное, чтобы проверить насколько быстро он работает. Так как набивать несколько тысяч строк — руки отвалятся, придумал сделать англо-русский словарь, тем более, что обрабатывать ввод одиночных английских слов я уже научился.

Сделал так же, как в версии под «Линукс» — bc переводится на ввод 36-ричных чисел. В таком режиме слова у нас становятся числами.

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

Так что я поступил иначе — проверяю версию bc и, если она достаточной новая (как под «Маком»), запускаю bc через tr, который заменяет буквы в нижнем регистре на буквы в верхнем. В этом случае, начало программы выглядит так:

#!/bin/sh
c=/*
tr -u a-z A-Z | bc -R "$0"
exit; */1

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

Сам словарь нашёлся в интернете. Чтобы не заливать в свой репозиторий чужую интеллектуальную собственность, я сделал make-файл, генерирующий мне программу на bc — словарь скачивается, распаковывается и обрабатывается специально написанной программой на Пайтоне. В итоге получается программа на пятьдесят тысяч с гаком строк.

В результате всё работает шустро, несмотря на линейный поиск. Я вообще не замечаю проблем с производительностью у bc, любопытно. Умели же делать!

Чтобы минимизировать программу по объёму, я сделал два цикла, а останов поиска делаю через break — он позволяет выйти из внутреннего цикла к началу внешнего:

while(c) while (c) {
ibase=36;c=read();ibase=A

if(c==19976){"Несколько";break}
/* тут очень много строк */
if(c==2813515210532){"Сухарь";break}
if(c==2174201762){"Зигота";break}
"Неизвестное слово";}
quit()

Ноль используется для выхода — у меня в Makefile есть небольшой тест, вот он и использует ноль, чтобы прекратить выполнение получившейся программы.

Результат, как обычно, можно увидеть в моём репозитории.