Я ищу способ заменить строки-заполнители в файле шаблона конкретными значениями с помощью общих инструментов Unix (bash, sed, awk, возможно, perl). Важно, чтобы замена выполнялась за один проход, то есть то, что уже отсканировано / заменено, не должно учитываться для другой замены. Например, эти две попытки терпят неудачу:
echo "AB" | awk '{gsub("A","B");gsub("B","A");print}'
>> AA
echo "AB" | sed 's/A/B/g;s/B/A/g'
>> AA
Правильный результат в этом случае, конечно, BA.
В общем случае решение должно быть эквивалентно сканированию ввода слева направо на предмет наибольшего совпадения с одной из заданных замещающих строк, а также для каждого совпадения, выполнения замены и продолжения с этого момента на входе (ни один из уже прочитанные вводные данные и выполненные замены должны учитываться для совпадений). На самом деле, детали не имеют значения, только то, что результаты замены никогда не рассматриваются для другой замены, полностью или частично.
ПРИМЕЧАНИЕ. Я ищу только правильные общие решения. Пожалуйста, не предлагайте решения, которые не подходят для определенных входных данных (входные файлы, поиск и замена пар), какими бы маловероятными они ни казались.
tr AB BA
.Ответы:
ОК, общее решение. Следующая функция bash требует
2k
аргументов; каждая пара состоит из заполнителя и замены. Вы сами должны заключить строки в кавычки, чтобы передать их в функцию. Если число аргументов нечетное, будет добавлен неявный пустой аргумент, который эффективно удалит вхождения последнего заполнителя.Ни заполнители, ни замены не могут содержать NUL-символов, но вы можете использовать стандартные C-
\
символы, например,\0
если вам нужныNUL
s (и, следовательно, вы должны писать,\\
если хотите a\
).Это требует стандартных инструментов сборки, которые должны присутствовать в posix-подобных системах (lex и cc).
Мы предполагаем, что
\
это уже экранировано, если необходимо в аргументах, но нам нужно экранировать двойные кавычки, если они есть. Это то, что делает второй аргумент для второго printf. Посколькуlex
действие по умолчанию -ECHO
нам не нужно беспокоиться об этом.Пример запуска (с таймингами для скептиков; это просто дешевый ноутбук):
Для больших входных данных может быть полезно предоставить флаг оптимизации
cc
, а для текущей совместимости с Posix было бы лучше использоватьc99
. Еще более амбициозная реализация может попытаться кэшировать сгенерированные исполняемые файлы, а не генерировать их каждый раз, но генерировать их не совсем дорого.редактировать
Если у вас есть tcc , вы можете избежать хлопот создания временного каталога и наслаждаться более быстрым временем компиляции, которое поможет при вводе данных нормального размера:
источник
fn() { tcc ; } <<CODE\n$(gen code)\nCODE\n
. Могу ли я спросить - это потрясающий ответ, и я проголосовал за него, как только прочитал, - но я не понимаю, что происходит с массивом оболочки? Что"${@//\"/\\\"}"
это делает?Нечто подобное всегда будет заменять каждое вхождение целевых строк только один раз, так как они встречаются
sed
в потоке с одним битом на строку. Это самый быстрый способ, которым я могу представить, что ты это сделаешь. Опять же , я не пишу C. Но это действительно надежно обрабатывать пустые разделители , если вы хотите его. Посмотрите этот ответ, чтобы узнать, как это работает. Это не имеет проблем с какими-либо содержащимися специальными символами оболочки или аналогичными - но это зависит от локали ASCII, или, другими словами,od
не будет выводить многобайтовые символы в одной строке и будет делать только один для каждого. Если это проблема, которую вы хотите добавитьiconv
.источник
sed
и сохранить до нуля или чего-то еще, чтобыsed
написать сценарий этого; или поместите его в функцию оболочки и присвойте ему значения по одному биту на строку, например"/$1/"
..."/$2/"
- может быть, я тоже напишу эти функции ...PLACE1
,PLACE2
иPLA
.PLA
всегда побеждает. ОП говорит: «эквивалентно сканированию входных данных слева направо на предмет наибольшего совпадения с одной из заданных замещающих строк» (выделение добавлено)perl
Раствор. Даже если некоторые заявили, что это невозможно, я нашел одно, но в целом простое сопоставление и замена невозможно, и даже это ухудшается из-за возврата NFA, результат может быть неожиданным.В целом, и это следует сказать, проблема дает разные результаты, которые зависят от порядка и длины заменяющих кортежей. то есть:
и ввод
AAA
результатов вBBB
илиCCB
.Вот код:
Checkerbunny:
источник