1

Тема: sed, perl та інша регекс-езотерика

Вирішив створити тему, в якій можна поділитися різними крутими штуками, зробленими на самих регексах (чи майже на самих). У першу чергу, програми, написані на sed, perl та інших подібних мовах. Хоча після успіху perl у 90-х практично в кожній сучасній мові з'явились інструменти для роботи з регулярними виразами — тому чітких обмежень нема, це може бути й php, Python, JS — за умови, що регулярні вирази є основним інструментом реалізації думки автора.

Наприклад, ось такий код:

#!/usr/bin/env sed -f
# Ханойська вежа
# Ввід: кількість дисків цифрами.
# Вивід: розв'язок задачі для заданої кількості дисків.
# Підтримуються числа в діапазоні від 1 до 999, 
# за умови достатньої кількості пам'яті та часу :)
s/[^0-9]//g
s/^/000/
s/.*\(.\)\(.\)\(.\)/\1C\2X\3I/
s/0[A-Z]//g
s/\(.\)\(.\)/\1987654321\2/g
s/\([0-9]\)[0-9]*\1//g
:roman
s/[0-9]\([A-Z]\)/\1\1/g
/[0-9]/broman
s/C/XXXXXXXXXX/g
s/X/IIIIIIIIII/g
s/./-/g
s/^..*$/A&B/
:loop
s/\([ABC]\)-\(--*\)\([ABC]\)/\1\2\1\3 \1-\3 \1\3\2\3/g
s/AB\|BA/C/g
s/AC\|CA/B/g
s/BC\|CB/A/g
/--/bloop
s/-/->/g

Або інша реалізація

#!/usr/bin/env sed -f
# Ханойська вежа (з використанням перекодування y/.../.../)
# Приймає числа 1...40
/^0$/bend
s/^/(A->B)/
# Конвертувати 10...40 в a...z,E,F,G,H :
/)1./y/0123456789/abcdefghij/
/)2./y/0123456789/klmnopqrst/
/)3./y/0123456789/uvwxyzEFGH/
s/).\(.\)$/)\1/
:loop
/1$/bend
h
y/AC/CA/
x
y/BC/CB/
G
s/)[^(]*(/ A->B /
y/123456789abcdefghijklmnopqrstuvwxyzEFGH/0123456789abcdefghijklmnopqrstuvwxyzEFG/
bloop
:end
s/[^-> ABC]//g

У другому варіанті вежі основним інструментом є не власне регекси, а простіший інструмент — перекодування. Завдяки цьому, програма працює трохи швидше, ніж попередня.
Обидва скрипти можуть приймати більші числа, ніж реально здатні обробити: оскільки увесь результат у процесі обробки тримається в оперативці, розв'язок задачі для 30 дисків вимагатиме декілька ГБ...

py -3 -m pip install git+https://github.com/snoack/python-goto
Подякували: ReAl1

2

Re: sed, perl та інша регекс-езотерика

Ну, вітаю! Вам вдалося із снайперської рушниці стріляючи гумовими кульками забити цвях на відстані 2 км.

Мій блог про ОС сімейства *nix - http://nixtravelling.blogspot.com/
Подякували: bvn1

3

Re: sed, perl та інша регекс-езотерика

При цьому, код займає не набагато більше, ніж якби я вибрав молоток. 20 рядків на sed проти 10 на паскалі — по моєму, доволі непогано.

py -3 -m pip install git+https://github.com/snoack/python-goto

4 Востаннє редагувалося P.Y. (21.11.2016 19:39:27)

Re: sed, perl та інша регекс-езотерика

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

#!/usr/bin/env sed -f
# Конвертер арабські цифри <=> римські цифри
# Підтримуються числа в діапазоні від 1 до 9999
/[0-9]/!btoarab
s/[^0-9]//g
s/^/000/
s/.*\(.\)\(.\)\(.\)\(.\)/\1M\2C\3X\4I/
s/0[A-Z]//g
s/\(.\)\(.\)/\1987654321\2/g
s/\([0-9]\)[0-9]*\1//g
:roman
s/[0-9]\([A-Z]\)/\1\1/g
/[0-9]/broman
s/CCCCC/D/
s/CCCC/CD/
s/DCD/CM/
s/XXXXX/L/
s/XXXX/XL/
s/LXL/XC/
s/IIIII/V/
s/IIII/IV/
s/VIV/IX/
b
:toarab
# конвертер з римських цифр в арабські
y/mdclxvi/MDCLXVI/
s/CM/DCD/g
s/XC/LXL/g
s/IX/VIV/g
s/\(M\)\([^MCD]\|$\)/\10C\2/g
s/\([CD]\)\([^CDXL]\|$\)/\10X\2/g
s/\([XL]\)\([^XLIV]\|$\)/\10I\2/g
:arab
s/0I/0/g
s/VIV\|IIIIIIIII/9/g
# (додаткові символи для вищих порядків не використовуються, 
# тому 4000...9000 записуються повтором знаку тисяч — 
# доводиться дублювати обидва формати)
s/IV/4/g
s/VIII\|IIIIIIII/8/g
s/VII\|IIIIIII/7/g
s/VI\|IIIIII/6/g
s/V\|IIIII/5/g
s/IIII/4/g
s/III/3/g
s/II/2/g
s/I/1/g
y/MDCLXVI/CLXVI?!/
/[VI]/barab
py -3 -m pip install git+https://github.com/snoack/python-goto