Разобрать строковый литерал Python

9

Задача состоит в том, чтобы проанализировать строку, как это делает Python, и распечатать ее содержимое.

  • Входные данные (аргумент командной строки или стандартный ввод) : строковый литерал (например, "hello") (или несколько литералов, см. Конкатенацию строкового литерала ниже)
  • Выход (stdout) : содержимое строки (например hello)

Правила разбора строки:

  • Строковый литерал заключен в соответствующие пары одинарных кавычек ( 'a'), двойных кавычек ( "a"), тройных одинарных кавычек ( '''a''') или тройных двойных кавычек ( """a"""). Первое повторение типа кавычек, открывших строку, завершает строку.
  • Обратная косая черта уходит: \' внутри строки становится ', \"становится "и \\становится \. Вам не нужно реализовывать любые другие обратные слэши. Обратная косая черта, которая не является частью escape-последовательности, остается обратной косой чертой.
  • Конкатенация строковых литералов: Содержимое смежных строковых литералов объединяется. Например, "hello" 'world'становится helloworld.
  • Входные данные могут содержать пробелы, которые не являются частью какого-либо литерала.
  • Вам не нужно поддерживать какие-либо другие виды пробелов, ни внутри, ни за пределами литералов.

Дополнительные правила:

  • eval, execИ подобные вещи не допускаются для разбора буквальных или его части.
  • Вы можете предположить, что ввод действителен.
  • Вы можете принять максимальную длину ввода 1023 символа.

Примеры:

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (без скобок, но с пробелами) -> """'''

Самый короткий код выигрывает.

flornquake
источник
Будет ли вывод иметь форму, которую можно сохранить, или достаточно распечатать его и покончить с этим?
DavidC
@ Дэвид Печать это все, что вам нужно сделать.
землетрясение
Таким образом, в (например) "\ z" код специально требуется для вывода обратной косой черты и z? Но \ 'становится просто апострофом, даже если он появляется внутри двойных или тройных кавычек? Это верно?
хлебница
@breadbox Точно.
землетрясение
Должен ли код поддерживать необработанные строки? А как насчет конкатенации необработанных и необработанных строк?
Бакуриу

Ответы:

4

Perl, 54 символа

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

Так же, как я публиковал это, я заметил, что это почти идентично решению Ruby от Jan Dvorak. Я немного расстроен тем, насколько это похоже на самом деле, но я собираюсь сказать: «Великие умы думают одинаково», и на этом все и закончится.

Эта программа подчеркивает странный случай в углу при подсчете символов в сценариях Perl. Насколько я понимаю, наличие одинарных кавычек в сценарии означает, что мне нужно посчитать -pопцию как два символа по отношению к общему количеству. Как правило, при вычислении размеров сценариев Perl начальный символ тире в опциях считается свободным, при условии, что он может быть связан с знаком, -eкоторый вводит саму программу ... но тогда вам также придется учитывать любые дополнительные побеги вам нужно ввести скрипт в командной строке. Одинарные кавычки требуют большого количества экранирования, поэтому, чтобы избежать этого штрафа, я должен считать его скриптом, запускаемым из файла, и поэтому получаю #!/usr/bin/perlбесплатно, но не любые дополнительные символы. Это немного сбивает с толку.

Хлебница
источник
2
Если хочешь быть другим, (('|")\2{2}?)такой же длины как("""|'''|"|')
Питер Тейлор
3

C, 178 символов

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);}

Это одно из тех решений C, где все делается внутри цепочки троичных операторов.

Программа работает, копируя символы обратно в тот же буфер, перезаписывая метасимволы. dсодержит разделитель внутри строки и tимеет значение true, если разделитель представляет собой тройную кавычку.

Хлебница
источник
Я думаю, что вам нужно включить условное дополнительное приращение переменной управления цикла. Для 'foo \\' bar 'он дает foo \ ar', который выглядит так, как будто он заменяет \\ на \, но затем продолжает синтаксический анализ с только что введенным \, рассматривая следующий токен как \ '.
Манатворк
На самом деле, этот пример неверный ввод. 'foo\\'ссылается на строку foo \, за которой следует символ, который не является ни пробелом, ни разделителем строк.
хлебница
К сожалению. Я неправильно понял это правило. Тогда, конечно, ваш код правильный.
Манатворк
3

Рубин, 74 73 персонажа

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

Ядром здесь являются два регулярных выражения: первое определяет границы строк и выбирает только содержимое. Изменения есть, чтобы удалить все, что не внутри строк, и это также сбрасывает открытые строки.Обратные слеши считаются необязательными, за которыми следует что угодно. Таким образом,Так как механизм регулярных выражений не будет возвращаться (\\?.)для правильных входных данных (спасибо @breadbox), единственная обратная косая черта не может соответствовать там. Кавычки обрабатываются через ленивое повторение. Затем второе регулярное выражение удаляет обратную косую черту перед каждым доступным символом. Регулярное выражение зависит от двигателя, который всегда выбирает самую левую альтернативу первой.

Я также рассмотрел подход конечного автомата, но он оказался довольно большим (19 состояний x 4 класса символов) по сравнению с решением регулярных выражений. Я все еще могу опубликовать состояние машины, если кто-то заинтересован.

Джон Дворак
источник
Один незначительный сбой этого метода: 'foo \\' bar 'становится foo \ вместо' foo \ 'bar'.
Манатворк
@manatwork это правильно, если что-то не было потеряно при форматировании. Первый обратный слеш избегает второго. 'foo\\'является первой строкой и bar'находится вне контекста строки, когда ввод'foo\\'bar'
Джон Дворжак
К сожалению. Понятия не имею, как я рассчитал это раньше. Конечно это правильно. Сожалею.
Манатворк
Когда я пытаюсь запустить это, я получаю сообщение об ошибке: «nested *? + In regexp». Есть ли какая-нибудь минимальная версия или флаг времени выполнения, которые мне нужны?
хлебница
@breadbox Я не проверял другие версии, но я использую ruby ​​1.9.3 (JRuby 1.7.2). я должен принять хотя бы 1.9.3 и отредактировать это в?
Джон Дворак