
Я использую perl для разбора множества многоязычных текстовых файлов. Мне нужно изменить текст между двумя шаблонами:
Желаемые изменения
Например, оригинальная версия на английском языке выглядит так:
\label{whatever}
\ref{whatever}
\autoref{whatever}
но текст между {
и }
должен быть дополнен соответствующим кодом языка ISO 639, например
\label{whatever_de}
\ref{whatever_de}
\autoref{whatever_de}
Предположения для тестирования
Имеются следующие файлы:
da/myfile_da.tex
de/myfile_de.tex
el/myfile_el.tex
en/myfile_en.tex
и каждый файл содержит:
\label{some_nice_thing}
\ref{some_nice_thing}
\autoref{some_nice_thing}
Мой подход
Я могу использовать имена папок в качестве кодов ISO 639 и создать простой цикл по файлам. Следующий код должен просто вывести измененные строки на консоль терминала. Я попытаюсь объяснить странные результаты, которые я получаю, на примере:
Работающий:\\label\{.*?\}
for f in *; do if [[ -d $f ]]; then perl -ne "print if s/(\\label\{.*?)\}/\1_$f\}/g" $f/myfile_$f.tex; fi; done
Не работает:\\ref\{.*?\}
for f in *; do if [[ -d $f ]]; then perl -ne "print if s/(\\ref\{.*?)\}/\1_$f\}/g" $f/myfile_$f.tex; fi; done
Не работает:\\autoref\{.*?\}
for f in *; do if [[ -d $f ]]; then perl -ne "print if s/(\\autoref\{.*?)\}/\1_$f\}/g" $f/myfile_$f.tex; fi; done
Обратите внимание, что это grep -Pr
работает в каждом случае (конечно, без удаления групп)
решение1
\\
становится \
в двойных кавычках. \\ref
становится , за \ref
которым на самом деле \r
следует ef
. Используйте четыре обратных слеша:
for f in *; do
if [[ -d $f ]]; then
perl -ne "print if s/(\\\\ref\{.*?)\}/\1_$f\}/g" $f/SystemRequirements_$f.tex
fi
done
Аналогично, \a
есть символ BELL ( \x07
).
решение2
Это проблема кавычек. Вы используете двойные кавычки для $f
переменной, но двойные кавычки также имеют другие последствия. В частности, они позволяют экранировать символы обратной косой чертой, поэтому \\
становится \
, когда достигает Perl:
$ printf "%s\n" "print if s/(\\label\{.*?)\}/\1_$f\}/g"
print if s/(\label\{.*?)\}/\1_\}/g
Это создает проблему с r
, поскольку \r
будет рассматриваться как символ возврата (см.perlrebackslash
) - не будет соответствовать r
. Вместо этого используйте одинарные кавычки, открывающиеся только для переменной:
$ printf "%s\n" 'print if s/(\\label\{.*?)\}/\1_'"$f"'\}/g'
print if s/(\\label\{.*?)\}/\1_\}/g