Проаналізуйте літеральний рядок Python


9

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

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

Правила розбору рядка:

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

Додаткові правила:

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

Приклади:

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (без дужок, але з пробілами) -> """'''

Найкоротший код виграє.


Чи має вигляд мати форму, яку можна зберігати, чи достатньо її надрукувати та зробити з нею?
DavidC

@David Друк - це все, що вам потрібно зробити.
flornquake

Отже, у (напр.) "\ Z" код спеціально необхідний для виведення зворотної косої риски та z? Але \ "стає просто апострофом, навіть якщо він з'являється всередині подвійних лапок або потрійних лапок? Це правильно?
хлібниця

@breadbox Рівно.
flornquake

Чи повинен код підтримувати необроблені рядки? А як щодо конкатенації несирих та сирих струн?
Бакуріу

Відповіді:


4

Perl, 54 символи

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

Щойно я публікував це, я помітив, що він майже ідентичний рішенню Ruby Яна Дворака. Мене трохи потурбує те, наскільки це схоже насправді, але я скажу «Великі розуми думають однаково» і відпущу це.

Ця програма підкреслює дивний кутовий випадок підрахунку символів у сценаріях 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є істинним, якщо роздільник є потрійною цитатою.


Я думаю, вам потрібно включити умовне додаткове збільшення змінної керування циклом. Для 'foo \\' bar 'він дає foo \ ar', схоже, що він замінює \\ на \, але потім продовжує розбір із щойно введеним \, бачачи наступний маркер як \ '.
манатура

Насправді цей приклад недійсний. 'foo\\'посилається на рядок foo \, за яким слідує символ, який не є ні пробілом, ні роздільником рядка.
хлібниця

На жаль Я неправильно прочитав це правило. Тоді звичайно ваш код правильний.
манатура

3

Рубі, 74 73 символи

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

Ядром тут є два регулярні вирази: Перший визначає межі рядків і вибирає лише вміст. Зміни є для того, щоб видалити все, що не знаходиться всередині рядків, і воно також випадає із незамкнених рядків.Поверхні боків розглядаються як позитивно-необов'язкові, за якими слід нічого. Таким чином,Оскільки двигун регулярного (\\?.)вирівнювання не повертається до дійсних входів (спасибі @breadbox), підошва ззаду не може відповідати. Цитати обробляються за допомогою ледачого повторення. Потім другий зворотний шрифт знімає зворотний нахил перед кожним символом, який можна отримати. Регекс залежить від двигуна, щоб завжди вибирати найкращу ліву альтернативу.

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


Один незначний збій при цьому методі: 'foo \\' bar 'стає foo \ замість' foo \ 'bar'.
манатура

@manatwork це правильно, якщо тільки щось не було втрачено у форматуванні. Перший зворотний проріз уникає другого. 'foo\\'є першим рядком і bar'знаходиться поза контекстом рядка, коли введення'foo\\'bar'
Джон Дворак

На жаль Поняття не маю, як я це раніше розраховував. Звичайно, це правильно. Вибачте.
манатура

Коли я намагаюся запустити це, я отримую повідомлення про помилку: "вкладене *? + В regexp". Чи потрібний якийсь мінімальний варіант або прапор виконання?
хлібниця

@breadbox Я не перевіряв інші версії, але в мене працює рубін 1.9.3 (JRuby 1.7.2). я повинен припустити 1.9.3 принаймні і відредагувати це в?
Джон Дворак
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.