Regex в обратном порядке - разложить регулярные выражения

16

Проблема

У меня есть куча регулярных выражений, которые мне нужно использовать в некотором коде, но я использую язык программирования, который не поддерживает регулярные выражения! К счастью, я знаю, что тестовая строка будет иметь максимальную длину и будет состоять только из печатного ASCII.

Соревнование

Вы должны ввести регулярное выражение и число n, и выход каждая строка состоит из печатной ASCII (ASCII коды от 32 до 126 включительно, до ~, ни вкладок или перевода строки) длины меньше или равно nчто совпадает с регулярным выражением. Вы не можете использовать встроенные регулярные выражения или функции сопоставления регулярных выражений в вашем коде вообще. Регулярные выражения будут ограничены следующим:

  • Литеральные символы (и escape-символы, которые заставляют символ быть буквальным, \.как и литерал ., \nявляются литералом n(эквивалентным просто n) и \wэквивалентны w. Вам не нужно поддерживать escape-последовательности.)
  • . - подстановочный знак (любой символ)
  • Классы символов, [abc]означает «a или b или c» и [d-f]означает что-нибудь от d до f (так, d или e или f). Единственными символами, которые имеют особое значение в классе символов, являются [и ](которые всегда будут экранированы, поэтому не беспокойтесь о них) \(escape-символ, конечно) ^в начале класса символов (который является отрицанием). ) и -(который является диапазоном).
  • |- оператор ИЛИ, чередование. foo|barозначает либо fooили bar, и (ab|cd)eсоответствует либо abeили cde.
  • * - сопоставить предыдущий токен, повторенный ноль или более раз, жадный (он пытается повторить столько раз, сколько возможно)
  • + - повторяется один или несколько раз, жадный
  • ? - ноль или один раз
  • Группировка с помощью скобок, группировать жетоны |, *. +, или?

Вход регулярное выражение всегда будет действительным (то есть, вы не должны обрабатывать ввод как ?abcили (fooили любой неверный ввод). Вы можете выводить строки в любом порядке, который хотите, но каждая строка должна появляться только один раз (не выводить дубликаты).

Тестовые случаи

Вход: .*, 1
выход: (пустая строка), , !, ", ..., },~

Вход: w\w+, 3
выход: ww,www

Вход: [abx-z][^ -}][\\], 3
выход: a~\, b~\, x~\, y~\,z~\

Вход: ab*a|c[de]*, 3
выход: c, cd, ce, aa, cde, ced, cdd, cee,aba

Вход: (foo)+(bar)?!?, 6
выход: foo, foo!, foofoo,foobar

Вход: (a+|b*c)d, 4
выход: ad, cd, aad, bcd, aaad,bbcd

Вход: p+cg, 4
выход: pcg,ppcg

Вход: a{3}, 4
выход:a{3}

Победитель

Это , поэтому выиграет самый короткий код в байтах!

Дверная ручка
источник
Разрешено ли нам поддерживать escape-последовательности? Тогда это тривиально.
Джон Дворак
3
Ваше объяснение |имеет очень мало смысла. Кажется, он не обрабатывает вложенные группы илиa|b|c . Что плохого в том, чтобы использовать стандартные объяснения с точки зрения того, насколько сильно связаны конкатенация и чередование? (И у вас нет оправданий для того, чтобы не использовать песочницу)
Питер Тейлор
1
@PeterTaylor На самом деле у него есть оправдание: meta.codegolf.stackexchange.com/q/1305/9498
Джастин
2
Судя по твоему примеру, шаблон должен соответствовать всей строке? (В отличие от подстроки)
Martin Ender
3
@KyleKanos Жаль, что проблемы реального мира не заставляют вас думать, что вы должны изучать регулярные выражения. : P Но они не так недоступны, как могут показаться: регулярные выражения.info/tutorial.html
Мартин Эндер

Ответы:

7

Haskell 757 705 700 692 679 667

import Data.List
data R=L Char|A R R|T R R|E
h=[' '..'~']
k(']':s)a=(a,s)
k('^':s)_=l$k[]s
k('-':c:s)(a:b)=k([a..c]++b)s
k('\\':c:s)a=k s$c:a
k(c:s)a=k s$c:a
l(a,b)=(h\\a,b)
c#E=L c
c#r=A(L c)r
o(a,b)=(foldr(#)E a,b)
t%0=E
t%n=A(t%(n-1))$T t$t%(n-1)
d s n=m(fst$r s)[[]] where{m E a=a;m(L c)a=[b++[c]|b<-a,length b<n];m(A r s)x=nub$(m r x)++m s x;m(T r s)a=m s$m r a;r s=w$e s E;w(u,'|':v)=(\(a,b)->(A u a,b))$r v;w x=x;e(')':xs)t=(t,xs);e s@('|':_)t=(t,s);e s@(c:_)t=g t$f$b s;e[]t=(t,[]);g t(u,v)=e v$T t u;f(t,'*':s)=(t%n,s);f(t,'+':s)=(T t$t%n,s);f(t,'?':s)=(A t E,s);f(t,s)=(t,s);b('(':s)=r s;b('\\':s:t)=(L s,t);b('.':s)=o(h,s);b('[':s)=o$k s[];b(s:t)=(L s,t)}

выход:

ghci> d ".*" 1
[""," ","!","\"","#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~"]
ghci> d "w\\w+" 3
["ww","www"]
ghci> d "[abx-z][^ -}][\\\\]" 3
["x~\\","y~\\","z~\\","b~\\","a~\\"]
ghci> d "ab*a|c[de]*" 3
["aa","aba","c","ce","cd","cee","cde","ced","cdd"]
ghci> d "(foo)+(bar)?!?" 6
["foo!","foobar","foo","foofoo"]
ghci> d "(a+|b*c)d" 4
["ad","aad","aaad","cd","bcd","bbcd"]
ghci> d "p+cg" 4
["pcg","ppcg"]
ghci> d "a{3}" 4
["a{3}"]

Пояснение: это реализация регулярного выражения в учебнике. R - это тип регулярного выражения с конструкторами A (альтернативный), L (буквальный), T (тогда) и E (пустой / эпсилон). Обычная «Звезда» не появляется, потому что во время разбора я добавляю ее как чередующиеся (см. «%»). m запускает симуляцию Парсер (начинающийся с 'rs = ....') - это просто рекурсивный спуск; 'k' разбирает диапазоны. Функция '#' расширяет диапазоны в чередования.

bazzargh
источник
7

Python v2.7 1069 1036 950 925 897 884 871 833 822

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

Две основные функции: fанализирует регулярное выражение, начинающееся с iсимвола th, и dгенерирует соответствующие строки, используяr под-регулярные выражения, в которые мы можем вернуться, 'a' массив, представляющий часть текущего под-регулярного выражения, еще не обработанную, и суффикс строки, sпредставляющий часть сгенерированной строки.

Также проверьте выход образца и тестовый жгут .

import sys;V=sys.argv;n=int(V[2]);r=V[1];S=len;R=range;C=R(32,127)
Z=[];z=-1;D='d(r,p,';F='for j in '
def f(i,a):
 if i>=S(r):return a,i
 c=r[i];x=0;I="|)]".find(c)
 if c in"([|":x,i=f(i+1,Z)
 if I+1:return([c,a,x],[a],[c,a])[I],i
 if'\\'==c:i+=1;x=c+r[i]
 return f(i+1,a+[x or c])
def d(r,a,s):
 if S(s)>n:return
 while a==Z:
        if r==Z:print s;return
        a=r[z];r=r[:z]
 e=a[z];p=a[0:z]
 if'|'==a[0]:d(r,a[1],s);d(r,a[2],s)
 elif']'==a[0]:
        g=a[1];N=g[0]=='^';g=(g,g[1:])[N];B=[0]*127;O=[ord(c[z])for c in g]
        for i in R(0,S(g)):
         if'-'==g[i]:exec F+'R(O[i-1],O[i+1]):B[j]=1'
         else:B[O[i]]=1
        for c in C:N^B[c]<1or d(r,Z,chr(c)+s)
 elif' '>e:d(r+[p],e,s)
 else:c=p[:z];exec{'.':F+'C:'+D+'chr(j)+s)','?':D+'s);d(r,p[:z],s)','*':F+'R(0,n+1):d(r,c,s);c+=[p[z]]','+':"d(r,p+['*',p[z]],s)"}.get(e,D+'e[z]+s)')
d(Z,f(0,Z)[0],"")

Обратите внимание, что вкладки в исходном решении были expandотредактированы. Для подсчета количества символов в оригинале используйте unexpand < regex.py | wc.

gmatht
источник
9
Я никогда не видел питона вид , что ужасно.
user80551
Вы не можете перейти def E(a,b):c=a[:];c.extend(b);return cна E=lambda a,b:a[:].extend(b), то же A
самое
Очевидно нет, так как .extend (b) ничего не возвращает.
Gmatht
1
Для elif isinstance(e,str):, я полагаю, вы можете изменить код внутри: exec{'.':'for c in C:d(r,p,s+chr(c))','?':'d(r,p,s);d(r,p[:z],s)','*':'''c=p[:z]#newline for i in R(0,n+1):d(r,c,s);c+=[p[z]]''','+':"d(r,p+['*',p[z]],s)",'\\':'d(r,p,e[1]+s)'}.get(e,'d(r,p,e+s)')(обратите внимание, что #newlineэто новая строка) (источник: stackoverflow.com/a/103081/1896169 )
Джастин
1
Если бы вы могли найти больше мест для использования трюка exec, мы могли бы легко превратить ваш код в нечитаемый код :-)
Justin