Analisar um literal de cadeia de caracteres Python

9

O desafio é analisar uma string como o Python e imprimir o conteúdo da string.

  • Entrada (argumento da linha de comando ou stdin) : uma literal de cadeia de caracteres (por exemplo "hello") (ou vários literais, consulte concatenação de literal de cadeia abaixo)
  • Saída (stdout) : o conteúdo da string (por exemplo hello)

Regras para analisar a sequência:

  • Um literal de cadeia é colocado entre pares de aspas simples ( 'a'), aspas duplas ( "a"), aspas simples triplas ( '''a''') ou aspas duplas triplas ( """a"""). A primeira recorrência do tipo de aspas que abriu a sequência finaliza a sequência.
  • A barra invertida escapa: \' dentro de uma cadeia torna-se ', \"torna "- \\se e torna - se \. Você não precisa implementar outras escapes de barra invertida. Uma barra invertida que não faz parte de uma sequência de escape permanece uma barra invertida.
  • Concatenação literal de string: o conteúdo dos literais de string adjacentes é concatenado. Por exemplo, "hello" 'world'torna-se helloworld.
  • A entrada pode conter espaços que não fazem parte de nenhum literal.
  • Você não precisa oferecer suporte a nenhum outro tipo de espaço em branco, nem dentro nem fora de literais.

Regras adicionais:

  • eval, exece coisas semelhantes não são permitidas para analisar o literal ou partes dele.
  • Você pode assumir que a entrada é válida.
  • Você pode assumir um comprimento máximo de entrada de 1023 caracteres.

Exemplos:

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (sem parênteses, mas com espaços) -> """'''

O menor código vence.

flornquake
fonte
A saída deve ter um formato que possa ser armazenado ou é suficiente para imprimi-la e terminar com ela?
18713
@ David Impressão, é tudo o que você precisa fazer.
Flornquake
Assim, em (por exemplo) "\ z", o código é especificamente necessário para gerar a barra invertida e o z? Mas "se torna apenas um apóstrofo, mesmo que apareça entre aspas duplas ou triplas? Isso está correto?
breadbox
@breadbox Exatamente.
Flornquake
O código deve suportar seqüências de caracteres brutas? E quanto à concatenação de cadeias não brutas e brutas?
Bakuriu 19/07/2013

Respostas:

4

Perl, 54 caracteres

#!/usr/bin/perl -p
s/ |("""|'''|"|')((\\?.)*?)\1/$2/g;s/\\(["'\\])/$1/g

Quando eu estava postando isso, notei que é quase idêntico à solução Ruby de Jan Dvorak. Estou um pouco impressionado com a sua similaridade, de fato, mas vou dizer "Grandes mentes pensam da mesma forma" e deixar para lá.

Este programa destaca um caso de canto estranho na contagem de caracteres nos scripts Perl: Pela minha leitura, a presença de aspas simples no script significa que preciso contar a -popção como dois caracteres em relação ao meu total. Normalmente, ao calcular o tamanho dos scripts Perl, o caractere inicial do traço nas opções é considerado livre, com a justificativa de que ele pode ser empacotado com o -eque introduz o programa corretamente ... você precisa inserir o script na linha de comando. As aspas simples exigem muito escape, portanto, para evitar essa penalidade, preciso contá-la como um script executado a partir de um arquivo e, portanto, recebo os caracteres #!/usr/bin/perlde graça, mas não os de opção. É um pouco confuso.

caixa de pão
fonte
2
Se você quer ser diferente, (('|")\2{2}?)tem o mesmo comprimento que("""|'''|"|')
Peter Taylor
3

C, 178 caracteres

char*p,*q,b[1024];d;main(t){for(p=q=gets(b);*p=*q++;)
d?*p==92&!(*q-*p&&*q-34&&*q-39)?*p++=*q++:*p-d||t&&*q-d|q[1]-d?++p:
(d=0,q+=2*t):*p-32?d=*p,t=*q==d&q[1]==d,q+=2*t:0;puts(b);}

Essa é uma daquelas soluções C em que tudo é feito dentro de um grupo de cadeias de operadores ternários.

O programa funciona copiando caracteres de volta para o mesmo buffer, substituindo os metacaracteres. dmantém o delimitador quando dentro de uma sequência e té verdadeiro se o delimitador for uma citação tripla.

caixa de pão
fonte
Eu acho que você precisa incluir um incremento extra condicional da variável de controle do loop. Para 'foo \\' bar ', fornece foo \ ar', que parece substituir \\ por \, mas continua a análise com o \ recém-inserido, vendo o próximo token como \ '.
manatwork
Na verdade, esse exemplo é uma entrada inválida. 'foo\\'refere-se à string foo \, que é seguida por um caractere que não é um espaço em branco nem um delimitador de string.
embalagem de pão
Opa Eu interpretei mal essa regra. Então é claro que seu código está correto.
manatwork
3

Rubi, 74 73 caracteres

puts gets.gsub(/('''|"""|'|")((\\?.)*?)\1|./,'\2').gsub /\\([\\'"])/,'\1'

O núcleo aqui são duas regexes: O primeiro determina os limites da cadeia e seleciona apenas o conteúdo. A alteração existe para remover tudo que não está dentro das cordas e também descarta as cordas não fechadas.As barras invertidas são tratadas como possesive-opcional seguidas por qualquer coisa. Portanto,Como o mecanismo regex não (\\?.)retornará para entradas válidas (obrigado @breadbox), uma única barra invertida não poderá corresponder lá. As cotações são tratadas por meio de repetição lenta. O segundo regex remove uma barra invertida antes de cada caractere escapável. A regex depende do mecanismo para sempre escolher a alternativa mais à esquerda primeiro.

Também considerei uma abordagem de máquina de estado, mas ficou bastante grande (19 estados x classes de 4 caracteres) em comparação com a solução regex. Ainda posso postar a máquina do estado se alguém estiver interessado.

John Dvorak
fonte
Uma pequena falha neste método: 'foo \\' bar 'se torna foo \ em vez de' foo \ 'bar'.
manatwork
@ manatwork isso está correto, a menos que algo tenha sido perdido na formatação. A primeira barra invertida escapa à segunda. 'foo\\'é a primeira corda e bar'está fora de um contexto de string quando a entrada é'foo\\'bar'
John Dvorak
Opa Não faço ideia de como eu o calculei anteriormente. Claro que está correto. Desculpa.
Manatwork
Quando tento executar isso, recebo uma mensagem de erro: "aninhado *? + No regexp". Existe alguma versão mínima ou sinalizador de tempo de execução necessário?
embalagem de pão
@breadbox Não verifiquei outras versões, mas estou executando o ruby ​​1.9.3 (JRuby 1.7.2). devo assumir pelo menos 1.9.3 e editá-lo em?
John Dvorak