Гаразд, загальне рішення. Наступна функція bash вимагає 2k
аргументів; кожна пара складається із заповнювача та заміни. Вам належним чином цитувати рядки, щоб передати їх у функцію. Якщо кількість аргументів непарна, буде доданий неявний порожній аргумент, який ефективно видалить входження останнього заповнювача.
Ні заповнювачі, ні заміни не можуть містити символів NUL, але ви можете використовувати стандартні C- \
діаграми, наприклад, \0
якщо вам потрібно NUL
s (і, отже, вам потрібно написати, \\
якщо ви хочете \
).
Для цього потрібні стандартні інструменти побудови, які повинні бути присутніми в системі, подібній до пози (lex та cc).
replaceholder() {
local dir=$(mktemp -d)
( cd "$dir"
{ printf %s\\n "%option 8bit noyywrap nounput" "%%"
printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
} | lex && cc lex.yy.c
) && "$dir"/a.out
rm -fR "$dir"
}
Ми припускаємо, що \
вже уникнути необхідності в аргументах, але нам потрібно уникати подвійних лапок, якщо вони є. Ось що робить другий аргумент другого printf. Оскільки lex
дія за замовчуванням є ECHO
, нам не потрібно про це турбуватися.
Приклад запуску (з термінами для скептичного; це просто дешевий товарний ноутбук):
$ time echo AB | replaceholder A B B A
BA
real 0m0.128s
user 0m0.106s
sys 0m0.042s
$ time printf %s\\n AB{0000..9999} | replaceholder A B B A > /dev/null
real 0m0.118s
user 0m0.117s
sys 0m0.043s
Для великих входів може бути корисно надати прапор для оптимізації cc
, а для поточної сумісності з Posix було б краще використовувати c99
. Ще більш амбітна реалізація може намагатися кешувати згенеровані файли, а не створювати їх щоразу, але їх генерувати не зовсім дорого.
Редагувати
Якщо у вас є tcc , ви можете уникнути клопоту щодо створення тимчасового каталогу та насолоджуватися швидшим часом компіляції, який допоможе нормальним розмірам даних:
treplaceholder () {
tcc -run <(
{
printf %s\\n "%option 8bit noyywrap nounput" "%%"
printf '"%s" {fputs("%s", yyout);}\n' "${@//\"/\\\"}"
printf %s\\n "%%" "int main(int argc, char** argv) { return yylex(); }"
} | lex -t)
}
$ time printf %s\\n AB{0000..9999} | treplaceholder A B B A > /dev/null
real 0m0.039s
user 0m0.041s
sys 0m0.031s
tr AB BA
.