Tokenizar um idioma baseado em pilha

15

Estive trabalhando outra linguagem de golfe baseada pilha chamada Stackgoat . Neste desafio, você escreverá um Tokenizer para Stackgoat (ou realmente qualquer linguagem geral baseada em pilha).

Exemplos

"PPCG"23+
["PPCG", '23', '+']

'a "bc" +
['"a"', '"bc"', '+']

12 34+-"abc\"de'fg\\"
['12', '34', '+', '-', '"abc\"de'fg\\"']

"foo
['"foo"']

(empty input)
[]

' ""
['" "', '""']

Especificação

Os três tipos com os quais você precisará lidar são:

  • Strings, qualquer coisa dentro""
  • Números, qualquer sequência de dígitos
  • Operadores, qualquer outro caractere único, além de espaço em branco

O espaço em branco é essencialmente ignorado, a menos que esteja dentro de uma string ou separe dois números.

Especificação de string / caractere:

  • As cadeias são delimitadas por a "e quando um\ é encontrada, o próximo caractere deve ser escapado.
  • Os caracteres são precedidos por ae 'o caractere após 'deve ser convertido em uma string literal. 'a->"a"
  • ' sempre terá um personagem depois
  • As aspas finais devem ser inseridas automaticamente

Regras:

  • Nenhuma forma de evalé permitida

Entrada / Saída:

  • A entrada pode ser obtida através de STDIN, parâmetros de função ou equivalente do seu idioma.
  • A saída deve ser uma matriz ou o equivalente mais próximo do seu idioma.
Downgoat
fonte
5
@Doorknob, sério?
LegionMammal978
4
@ LegionMammal978 Sim, sério.
Alex A.
1
A saída pode ser para STDOUT?
Maçaneta
2
@ZachGates Bem, sim, a maioria dos idiomas também manipula \ como um caractere de escape, então sim, você precisará escapar disso se o seu idioma precisar obviamente.
Downgoat
1
Além disso, no primeiro exemplo, o primeiro elemento do resultado deve ser em '"PPCG"'vez de apenas "PPCG"?
Fund Monica's Lawsuit

Respostas:

8

Retina , 68 64 63 bytes

M!s`"(\\.|[^"])*"?|'.|\d+|\S
ms`^'(.)|^"(([^\\"]|\\.)*$)
"$1$2"

ou

s`\s*((")(\\.|[^"])*(?<-2>")?|'.|\d+|.)\s*
$1$2¶
\ms`^'(.)
"$1"

Eu acho que isso abrange todos os casos extremos, até mesmo aqueles não cobertos pelos casos de teste do desafio.

Experimente online!

Martin Ender
fonte
Dang, isso é curto. Bem feito!
Fund Monica's Lawsuit
Consegui traduzir isso em uma função ES6 de 95 bytes. Seria 80, exceto que os regexps não funcionam ao contrário (muitos casos extremos).
Neil
2

Ruby, 234 bytes

puts"[#{$stdin.read.scan(/("(?:(?<!\\)\\"|[^"])+(?:"|$))|'(.)|(\d+)|(.)/).map{|m|(m[0]?(m[0].end_with?('"')?m[0]: m[0]+'"'): m[1]?"\"#{m[1]}\"": m.compact[0]).strip}.reject(&:empty?).map{|i|"'#{/\d+|./=~i ?i: i.inspect}'"}.join', '}]"

Eu tentei usar o find(&:itself) truque que vi ... em algum lugar, mas aparentemente .itselfnão é realmente um método. Além disso, estou trabalhando para reduzir a regex, mas já é ilegível.

Se não precisarmos produzir de maneira sofisticada (por exemplo, as strings não precisam ser citadas na matriz), posso salvar um lote inteiro de bytes:

Ainda Ruby, 194 bytes:

p$stdin.read.scan(/("(?:(?<!\\)\\"|[^"])+(?:"|$))|'(.)|(\d+)|(.)/).map{|m|(m[0]?(m[0].end_with?('"')?m[0]: m[0]+'"').gsub(/\\(.)/,'\1'): m[1]?"\"#{m[1]}\"": m.compact[0]).strip}.reject(&:empty?)

Tenho certeza de que posso jogar mais, mas não sei bem como.


Ungolfed em breve. Comecei a mexer com o jogador de golfe diretamente em algum momento e terei que provocá-lo.

Fund Processo de Monica
fonte
0

Python 3, 228 bytes

import re;L=list
print(L(map(lambda i:i+'"'if i[0]=='"'and not i[-1]=='"'else i,map(lambda i:'"%s"'%i[1]if i[0]=="'"else i,filter(None,sum([L(i)for i in re.findall('(\'.)|(".*")|(\d+)|([^\w\"\'\s\\\])|(".*"?)',input())],[]))))))

Aqui está um belo, longo, dois forros.


Teste-o no Python 3. Aqui estão alguns exemplos:

$ python3 test.py
"PPCG"23+
['"PPCG"', '23', '+']

$ python3 test.py
'a "bc" +
['"a"', '"bc"', '+']

$ python3 test.py
12 34+-"abc"de'fg\"
['12', '34', '+', '-', '"abc"de\'fg\\"']

$ python3 test.py
"foo
['"foo"']

$ python3 test.py

[]

$ python3 test.py
' ""
['" "', '""']
Zach Gates
fonte