Потому что мы не можем насытиться эзотерическими языками, не так ли?
/// - произносится косая черта - забавный маленький язык, основанный на s///
функции замены регулярных выражений славы Perl. Он содержит только два специальных символа, косую черту /
и обратную косую черту \
. Вы можете найти полную статью об этом на вики- сайте esolangs , но я приведу описание языка ниже, а также некоторые примеры.
Короче говоря, это работает, идентифицируя /pattern/repl/rest
в программе и делая замену столько раз, сколько возможно. Никакие символы не являются специальными, за исключением /
и \
: /
разграничивает шаблоны и замены в программе, а также \
позволяет вставлять литералы /
или \
символы в ваш код. Примечательно, что это не регулярные выражения, а просто подстановки строк.
Ваша задача состоит в том, чтобы создать интерпретатор для языка /// в виде программы, читающей STDIN, или функции, принимающей строковый аргумент, в минимально возможном количестве символов.
Вы можете использовать любой язык, кроме самого ///. Вы не можете использовать любые библиотеки, которые интерпретируют ///; вы можете, однако, использовать регулярные выражения, библиотеки регулярных выражений или библиотеки соответствия строк.
выполнение
Существует четыре состояния: печать , рисунок , замена и замена . В каждом штате, кроме замены :
- Если программа пуста, выполнение останавливается.
- Иначе, если первый символ есть
\
, сделайте что-нибудь со следующим символом (если он есть) и удалите оба из программы. - Иначе, если первый символ есть
/
, удалите его и перейдите к следующему состоянию. - Иначе, сделайте что-нибудь с первым символом и удалите его из программы.
- Повторение.
Состояния циклически изменяются в порядке печати , рисунка , замены и замены .
- В режиме печати «сделать что-то» означает вывод символа.
- В режиме паттерна «сделать что-то» означает добавить символ в текущий паттерн.
- В режиме замены «сделать что-то» означает добавить персонажа к текущей замене.
В режиме замены вы следуете другому набору правил. Повторно заменяйте первое вхождение текущего образца на текущую замену в программе, пока больше не будут возможны замены. В этот момент очистите шаблон и замену и вернитесь в режим печати .
В программе /foo/foobar/foo foo foo
происходит следующее:
/foo/foobar/foo foo foo
foo foo foo
foobar foo foo
foobarbar foo foo
foobarbarbar foo foo
...
Это зацикливается навсегда и никогда не выходит из режима замены . Точно так же, если шаблон пуст, то первое совпадение с пустой строкой - в начале программы - всегда совпадает, поэтому режим замены зацикливается навсегда, никогда не останавливаясь.
Примеры
no
Выход: no
.
/ world! world!/Hello,/ world! world! world!
Выход: Hello, world!
.
/foo/Hello, world!//B\/\\R/foo/B/\R
Выход: Hello, world!
.
a/ab/bbaa/abb
Выход: a
. Программа не останавливается.
//
Выход: нет.
///
Выход: нет. Программа не останавливается.
/\\/good/\/
Выход: good
.
В вики есть также quine, которую вы можете попробовать.
источник
/-/World//--/Hello//--W/--, w/---!
Что не любить? (Попробуйте убрать тире с конца)\
экранирует любой следующий за ним символ, в том числе/
, который впоследствии можно использовать как обычно. Хотя это выглядит не так много, это делает /// Тьюринг-завершенным .///
IDE, что я делаю!Ответы:
APL (133)
Это функция, которая принимает
///
код в качестве правильного аргумента.Неуправляемый, с объяснением:
источник
///
и//foo/
(то есть циклы навсегда)?/
все равно останется в этой точке.J -
181190170 символовЭто был кошмар. Я переписал его с нуля, дважды, потому что он просто продолжал беспокоить меня. Это функция, принимающая единственный строковый аргумент, выводящий в STDOUT.
Чтобы объяснить, я разобью его на подвыражения.
i
(сокращение от итерации ) - наречие. Он принимает аргумент глагола слева и возвращает глагол(f)i
, который при применении к аргументуf
неоднократно применяется к аргументу до тех пор, пока не произойдет одно из двух: он не найдет фиксированную точку (y = f y
) или не выдаст ошибку. Поведение с фиксированной запятой присуще^:_
и::]
обрабатывает ошибки.parse
токенизирует входные данные в то, что я называю полуразборенной формой, а затем обрезает их в неэкранированном «/» Он связывает экранирование с обратным слешем с их персонажами, но не избавляется от обратного слеша - так что мы можем либо отменить его, либо завершить его в зависимости от того, что мы хотим.Основная часть интересных работ происходит в
;:
. Это примитив последовательного машинного интерпретатора, который содержит описание машины ((0;(0,:~1 0,.2);'\';&<1 0)
) слева и кое-что для анализа справа. Это делает токенизацию. Я отмечу, что эта конкретная машина на самом деле относится к первому символу как к особенной, даже если она\
и должна быть привязана. Я делаю это по нескольким причинам: (1) таблица состояний более проста, так что ее можно играть дальше; (2) мы можем легко добавить фиктивного персонажа впереди, чтобы избежать проблемы; и (3) этот фиктивный персонаж наполовину разбирается без каких-либо дополнительных затрат, поэтому я могу использовать его для настройки на фазу обрезки, затем.Мы также используем,
<;._1
чтобы вырезать токенизированный результат на unescaped/
(это то, что я выбрал, чтобы быть первым ). Это удобно для извлечения вывода, шаблона и замены изout/patt/repl/rest
всех за один шаг, но, к сожалению, также сокращает остальную часть программы, где мы нуждаемся в том,/
чтобы они оставались нетронутыми. Я склеиваю их обратно во времяeval
, потому что если<;._1
оставить их в покое, это будет стоить намного дороже.Вилка
(eval [ print)
выполняетprint
на результат из-parse
за его побочных эффектов, а затем запускаетсяeval
.print
это простой глагол, который открывает первое поле (которое мы точно знаем, это вывод), заканчивает его разбор и отправляет в STDOUT. Тем не менее, мы также пользуемся возможностью определить вспомогательный глаголp
.p
определяется как>@{.@[
, поэтому он принимает свой левый аргумент (действует как идентификатор, если дан только один аргумент), берет первый элемент этого (идентификатор при наличии скаляра) и распаковывает его (идентификатор, если он уже распакован). Это очень пригодитсяsub
.eval
оценивает остаток обработанной программы. Если у нас нет полного шаблона или полной замены,eval
он выбрасывает его и просто возвращает пустой список, который завершает оценку;:
из-заparse
ошибки (from ) на следующей итерации. Иначе,eval
полностью анализирует шаблон и замену, исправляет оставшуюся часть источника, а затем передает обаsub
. Взрывом:sub
где происходит один (возможно, бесконечный) раунд замен. Из-за того, как мы настроилиeval
, источник является правильным аргументом, а шаблон и замена объединены в левом. Поскольку аргументы упорядочены следующим образом, и мы знаем, что шаблон и замена не меняются в цикле подстановок, мы можем использовать другую функциюi
- тот факт, что он изменяет только правый аргумент и продолжает передаваться в том же левом - для делегирования J нужно беспокоиться о отслеживании состояния.Однако есть две проблемы. Во-первых, у глаголов J может быть не более двух аргументов, поэтому у нас нет простого способа получить доступ к любому из них, например, к шаблону и замене, здесь. Благодаря разумному использованию
p
утилиты, которую мы определили, это не такая большая проблема. Фактически, мы можем получить доступ к шаблону одним символом, просто используяp
его>@{.@[
определение: Unbox of the First item левого аргумента. Получить замену - сложная задача, но самый короткий путь будет наp&|.
2 знака короче, чем вытащить ее вручную.Вторая проблема заключается в том, что происходит
i
выход в фиксированных точках, а не в цикле навсегда, и если шаблон и замена равны, и вы делаете подстановку, которая выглядит как фиксированная точка для J. Мы справляемся с этим, вводя бесконечный цикл с отрицанием 1 над более, если мы обнаружим, что они равны: это-i@=`p@.~:~/
часть, заменяющаяp&|.
.Этот цикл повторяется из-за использования
i
до тех пор, пока что-то выходит за пределыsub
ошибки. Насколько я знаю, это может произойти только тогда, когда у нас не будет символов, или когда мы выбрасываем неполный набор шаблонов и замен.Интересные факты об этом гольфе:
;:
короче, чем ручная итерация по строке.0{
должен иметь шанс на ошибку доsub
перейдет в бесконечный цикл, так что это должно работать нормально, если шаблон соответствует замене, но никогда не отображается в оставшейся части источника. Тем не менее, это может или не может быть неопределенным поведением, так как я не могу найти цитату в любом случае в документах. Whoopsie.i
, эти ошибки тоже попадают в ловушку. В зависимости от того, когда вы нажмете Ctrl + C, вы можете:sub
цикла и попытайтесь объединить число в строку, а затем продолжайте интерпретировать ///, как если бы вы закончили замену строки самим собой бесконечное число раз.sub
на полпути и продолжайте интерпретировать выражение /// наполовину подобласти.Пример использования:
источник
/\\/good/\/
тестового примера; отладка говорит мне, что проблема в том, что я использую1!:2&4
, так как у jqt нет stdin / out. Будем расследовать. Какие у тебя9!:12''
и9!:14''
?9!:12''
6 и9!:14''
является j701 / 2011-01-10 / 11: 25.Perl - 190
Читает
///
программу от стандартного до EOF.источник
m/^(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*)$/s
совпадаем ли с выходом, схемой и заменой одновременно» сделать более короткий гольф? Сам я не знаю Perl./a/\0/a
Пип ,
100102 байтаЯ никогда не доказывал, что Пип является завершенным по Тьюрингу (хотя это вполне очевидно), и вместо того, чтобы идти по обычному маршруту БФ, я подумал, что /// будет интересно. Как только у меня было решение, я решил, что я буду играть в гольф и выложить его здесь.
101 байт кода, +1 для
-r
флага:Вот моя неутешительная версия с обильными комментариями:
Попробуйте онлайн! (Обратите внимание, что TIO не выдает никаких выходных данных, когда программа не завершается, а также имеет ограничение по времени. Для более крупных примеров и бесконечных циклов рекомендуется запуск Pip из командной строки.)
источник
pip + -r
, 101 байтC ++: Visual C ++ 2013 = 423, g ++ 4.9.0 = 442
Это никогда не победит, но так как я решил, что все мои будущие программные проекты будут написаны на этом потрясающем языке, мне понадобился переводчик, и я подумал, что мог бы поделиться тем, что я сделал ...
Разница в баллах заключается в том, что Visual C ++ не нуждается в первом включении, а в g ++. Оценка предполагает, что окончания строки считаются за 1.
источник
if(!o[i]);
так ,if(P
чтобы сохранить символы, или я недоразумение как #define работает?P
inmain
имеет пробел после него, поэтому вы можете сохранить символ, заменив эти пробелы точкой с запятой и удалив его из#define
. Затем, если вы можете использовать там#define
внутри других, вы можете сэкономить еще немного переписав ,N(x)
как(92==P
вместо того ,o[i]==92
иO
таким же образом.N(x)
какP;else if(n<x)(P==92?
и изменение вызововN
соответственно может сэкономить несколько байт.Python 2 (236), Python 3 (198?)
Называется как
d(r"""/foo/Hello, world!//B\/\\R/foo/B/\R""")
. Тройные кавычки нужны только если///
программа содержит новые строки: в противном случае простые кавычки в порядке.РЕДАКТИРОВАТЬ: Этот интерпретатор теперь печатает материал, как ожидалось (ранее он печатался только в самом конце, см. Комментарии). Для Python 3 удалите первую строку (но у меня нет Python 3 в моей старой установке, поэтому я не могу быть уверен, что других изменений нет).
источник
/a/ab/bbaa/abb
./a/ab/bbaa/abb
застрянет в бесконечном цикле, ничего не печатая, потому что первая замена -a
=>ab
. Правильноa/ab/bbaa/abb
работает как рекламируется.-u
чтобы заставить буфер вывода быть небуферизованным.Кобра - 226
источник
Руби ,
119110 байтЗавершается с исключением
Попробуйте онлайн!
Завершает чисто (116 байт)
Попробуйте онлайн!
источник
Python 2/3 (211 байт)
Следующий код, основанный на ответе Бруно Ле Флоша , совместим с Python 2 и Python 3.
Более того, будучи итеративным, а не рекурсивным, он не рискует достичь максимальной глубины рекурсии Python.
источник
in(0,1,2)
в гольфin 0,1,2
и[""]*2+[1]
обратно["","",1]
, в результате чего получается 211 байт .BaCon ,
391387395 байтИз вкладов на этой странице я получил только программу Python для работы. Другие работают для некоторых /// образцов или не работают вообще. Поэтому я решил добавить свою версию, которая является реализацией в BASIC.
Соревноваться в соревнованиях CodeGolf с BASIC непросто, так как BASIC использует длинные слова в качестве утверждений. Единственная аббревиатура, обычно встречающаяся в бейсике, это «?» знак, что означает печать.
Таким образом, приведенная ниже программа может никогда не победить, но, по крайней мере, она работает со всем демонстрационным кодом на этой странице Codegolf и в Esolangs Wiki . Включая все версии "99 бутылок пива".
источник