Предположим, есть текст из файла:
(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 23" "#2")
("Exercises 31" "#30")
("Notes and References 42" "#34"))
)
Я хочу добавить 11 к каждому числу, за которым следует a "
в каждой строке, если оно есть, т.е.
(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 34" "#13")
("Exercises 42" "#41")
("Notes and References 53" "#45"))
)
Вот мое решение с использованием GNU AWK и regex:
awk -F'#' 'NF>1{gsub(/"(\d+)\""/, "\1+11\"")}'
т.е. я хочу заменить (\d+)\"
на \1+10\"
, где \1
группа, представляющая (\d+)
. Но это не работает. Как я могу заставить это работать?
Если gawk не лучшее решение, что еще можно использовать?
Ответы:
Попробуй это (ткнуть нужно).
Протестируйте на своем примере:
Обратите внимание, что эта команда не будет работать, если два числа (например, 1 "и" # 1 ") различны или в этой строке больше номеров с этим шаблоном (например, 23" ... 32 "..." # 123 ") в одну строку.
ОБНОВИТЬ
Поскольку @Tim (OP) сказал, что число, за которым следует одна и та
"
же строка, может отличаться, я внес некоторые изменения в свое предыдущее решение и заставил его работать для вашего нового примера.Кстати, из примера я чувствую, что это может быть таблица структуры контента, поэтому я не вижу, как эти два числа могут различаться. Сначала будет напечатан номер страницы, а 2 с # будет индекс страницы. Я прав?
Во всяком случае, вы знаете свое требование лучше всего. Теперь новое решение, все еще с gawk (я делю команду на строки, чтобы было легче читать):
протестируйте с вашим новым примером:
EDIT2 на основе комментария @Tim
Вы правы для разделителя как во входной, так и в выходной части. Он определил разделитель как:
Есть две двойные кавычки, потому что легче поймать два числа, которые вы хотите (на основе вашего примера ввода).
Точно!
Это из http://www.gnu.org/s/gawk/manual/html_node/String-Functions.html . Вы можете прочитать, чтобы получить подробное использование gensub.
источник
awk -F'#'
кажется, что вы хотите вносить изменения только после '#'?FS=OFS="\" \"#"
означает ли разделитель поля как на входе, так и на выходе двойные кавычки, пробел, двойные кавычки и #? зачем указывать двойную кавычку дважды? (2) в/.* ([0-9]+)$/
,$
означает ли конец строки? (3) в третьем аргументе gensub (), в чем разница между"g"
и"G"
?В отличие от почти всех инструментов, которые предоставляют подстановки регулярных выражений, awk не допускает обратных ссылок, таких как
\1
текст замены. GNU Awk предоставляет доступ к соответствующим группам, если вы используетеmatch
функцию , но не с помощью~
илиsub
илиgsub
.Также обратите внимание, что даже если
\1
это поддерживается, ваш фрагмент будет добавлять строку+11
, а не выполнять численные вычисления. Кроме того, ваше регулярное выражение не совсем верно, вы подходите к вещам вроде"42""
и нет"#42"
.Вот решение awk (предупреждение, не проверено). Он выполняет только одну замену на строку.
Было бы проще в Perl.
источник
awk
может сделать это, но это не напрямую, даже с использованием обратных ссылок.GNU awk имеет (частичную) обратную ссылку в форме gensub .
Экземпляры
123"
временно обертываются\x01
и\x02
помечаются как неизмененные (дляsub()
. CoИли вы можете просто пройтись по циклу, изменяя кандидатов по ходу дела, в этом случае обратная ссылка и «скобки» не нужны; но отслеживание индекса символов необходимо.
Вот еще один способ, используя
gensub
и массивsplit
и\x01
как разделитель полей (для разделения ). \ X02 помечает элемент массива как кандидата на арифметическое сложение.источник
"\x01\\1\"\x02"
значит? Я до сих пор не понимаю\x01
и\x02
. (2) насколько отличается возврат$0
отgensub
и$0
как последний аргументgensub
?\x01
и\x02
используются в качестве маркеров замещения. Эти значения являются весьма маловероятно , чтобы быть в любом обычном текстовом файле, поэтому они одинаково «высоко» безопасно для использования (то есть. Не столкнуться столкновение с уже существующими) .. Они просто временные метки .. Re$0=gensub(... $0)
.. видеть это link String-Manipulation Functions , но в итоге: он (gensub) возвращает измененную строку в результате выполнения функции, и исходная целевая строка не изменяется. ...$0=
Просто изменяет исходную цель ..Поскольку решения в (g) awk кажутся довольно сложными, я хотел добавить альтернативное решение в Perl:
Объяснение:
-w
включает предупреждения (которые будут предупреждать вас о возможных нежелательных эффектах).-p
подразумевает цикл вокруг кода, который работает аналогично sed или awk, сохраняя каждую строку ввода автоматически в переменной по умолчанию$_
.-e
сообщает Perl, что программный код следует в командной строке, а не в файле сценария.s/.../.../
)$_
, где последовательность цифр, если после нее следует буква a"
, будет заменена на последовательность, интерпретируемую как число в сложении плюс 11.(?=pattern)
ищет ,"
не принимая его в матче, так что мы не должны повторять его замены. Переменная MATCH$&
в замене будет содержать только число./e
Модификатор регулярного выражения говорит ,perl
чтобы «выполнить» замену в качестве кода вместо того , чтобы принимать его в виде строки./g
Модификатор делает замену «глобальной», повторяя это на каждом матче в линии.К
$&
сожалению, переменная MATCH отрицательно скажется на производительности кода в версиях Perl до 5.20. Более быстрое (и не намного более сложное) решение будет использовать$1
вместо этого группирование и обратную ссылку :И если предварительное утверждение выглядит слишком запутанным, вы также можете явно заменить кавычку:
источник