Вложенный условный поиск и замена на месте - PullRequest
0 голосов
/ 22 ноября 2018

Я новичок в awk.У меня есть файл, который выглядит так:

beans and celery  
beans and oatmeal  
beans and beans  
quinoa
<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>

Я пытаюсь выполнить поиск и заменить на месте тег "fo".Я хочу захватить начало тега, а также параметр "src".Обратите внимание, что положение тега src варьируется от строки к строке!

Я смог получить нужные поля, используя следующее:

awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i}}' inventory.txt

Как я могу сделатьзамена этого на месте?Я также хочу добавить строку к новому содержимому строки.Я пробовал:

awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i "misc stuff here"}}' inventory.txt

Но это полностью портит порядок получающейся строки, которую я хочу иметь в форме:

<fo:external-graphic src="url(images/image1.png)" misc stuff here

PS1: Дополнительные пояснения о том, чтоРезультат, который я хочу: Файл содержит строки вроде:

<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>

Я хочу обработать их и получить вывод, например:

<fo:external-graphic src="url(images/image1.png)" _completely new stuff here, till end of string_ />

, например:

<fo:external-graphic src="url(images/image1.png)" age="25" sex="M" />

Я хочу, чтобы результат ВСЕГДА начинался с:

<fo:external-graphic src="url(images/image1.png)"

, затем дополнительный материал, например:

age="25" sex="M" />

Никакая другая часть исходной строки не требуется в конечном выводе.

PS2: Можно ли упаковать все это в gsub?Насколько мне известно, gsub принимает только два аргумента.Я пытался составить сложное выражение для аргумента замены, но оно не работает, например:

gawk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") gsub($0, "boy band"); {print}}}' inventory.txt > testres

PS3: Это всего лишь наблюдение новичка, может быть, я ошибаюсь.Рассмотрим файл со следующим содержимым:

Donald Trump
Donald Duck
George Bush
Steve Austin

Регулярное выражение для поиска всех строк, начинающихся с Дональда:

/^Donald/

Если я хочу заменить все вхождения «Дональд»с "Barrack" я мог бы сделать следующее:

gawk -i inplace '{ gsub(/^Donald/, "Barrack"); { print } }' FILENAME

Если я хочу полностью изменить все строки, которые содержат "Donald", я бы сделал:

gawk -i inplace '{ gsub(/^Donald.*/, "Barrack"); { print } }' FILENAME

gawk и gsub, по-видимому, заменяют только span или любую часть строки, соответствующую заданному регулярному выражению.Таким образом, если я хочу полностью изменить всю строку, мое регулярное выражение должно охватывать всю эту строку.

PS4: Просто чтобы устранить любые неясности в отношении ожидаемого решения.Учитывая следующий файл:

<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic width="6.3in" height="auto" src="url(images/image1.png)" content-width="246px" content-height="322px"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" content-width="246px" content-height="322px"/>

Я ищу решение awk / gawk, которое заменит этот файл на:

<fo:external-graphic src="url(file:/C:/Users/xxx/images/tip.svg)" age="25" sex="M" />
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>

Целевой файл должен быть изменен .

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

РЕДАКТИРОВАТЬ3: Добавление еще одного кода здесь в соответствии с новым редактированием OP.

awk  '
/ width.*content-width.*src/{
  sub(/ width.*content-width.*src/," src")
  sub(/\/>$/," age=\"25\" sex=\"M\"&")
}
/src.*width/{
  match($0,/src[^)]*/)
  val=substr($0,RSTART,RLENGTH+2)
  sub(/src.*/,"")
  $0=$0 OFS val OFS "age=\"25\" sex=\"M\"/>"
}
1
'  Input_file


EDIT2: Для изменения полной строки относительно PS3 OP, пожалуйста, попробуйте следующее.

awk '/^Donald/{$0="new_line_value"} 1'  Input_file
new_line_value
new_line_value
George Bush
Steve Austin


РЕДАКТИРОВАТЬ: Поскольку OP изменил ожидаемый результат, добавьте также решение в соответствии с этим выходом.

awk '/^<fo:external-graphic src=.*/ && match($0,/src=.*\)\"/){$0=substr($0,1,RSTART+RLENGTH) " new_value_bla_bla_here.. />"} 1' Input_file


Не могли бы вы попробовать следующее (не проверили его полностью, так как ожидаемый результат неclear).

awk '
/^<fo:/ && match($0,/src=.*>/){
  $0=substr($0,1,RSTART-1) OFS "new_value_here.." OFS substr($0,RSTART+RLENGTH+1)
}
1
'  Input_file

В этом коде проверяется строка, которая начинается со строки <fo:, а затем выполняется попытка перехватить строку с src= до / на match и заменить захваченный текст новымстрока здесь.

Если вы хотите сохранить выходные данные в сам файл Input_file, добавьте > temp_file && mv temp_file Input_file в приведенный выше код.

0 голосов
/ 22 ноября 2018

Ваша попытка верна, но при условии, что ваше намерение добавить только к слову, начинающемуся с src, т. Е. К $i, примените действие только для этого поля и оставьте остальные поля без изменений

awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") $i = $i " misc stuff here"}}1' inventory.txt

Часть $i = $i " misc stuff here" выполняет действие по добавлению строки только в поля, соответствующие вашему условию регулярного выражения.Обратите внимание на удаление print и добавление {..}1 в конце.Что это в основном означает, так это перестроить всю строку на основе изменений, сделанных внутри {..}.Поскольку мы модифицируем только определенные поля, остальные остаются без изменений.

Если вы хотите переписать все поле, начиная с src, и добавить некоторую строку, используйте правильное соответствие регулярному выражению с gsub()и добавьте строку после сопоставленного текста, обозначенного &

awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) { if ($i ~ "src") gsub(/src=\"url([^"]*)\"/, "& new string", $i ) }}1' inventory.txt

Из самого последнего редактирования OP кажется, что OP просто хочет, чтобы поле src было изменено с добавлением новой строки в конце.Кажется, остальные поля можно игнорировать.Использование match() в GNU awk имеет дополнительное преимущество, заключающееся в добавлении третьего параметра для сохранения захваченных групп как

awk -v newstr="age=\"25\" sex=\"M\"" 'match($0, /^(<fo:external-graphic).*(src=\"url([^"]*)\").*(\/>)$/, arr){ print arr[1]" "arr[2]" "newstr""arr[4]  }' file

. Обратите внимание, что GNU awk не имела модификаций на месте вплоть до версии 4.1.2, на котором вы можете просто сделать

gawk -i inplace '{...}' inventory.txt

Для версий, более ранних к этому, используйте временный файл

awk '{...}' inventory.txt > tmpfile && mv tmpfile inventory.txt

Или, если вы moreutils установлены, используйте sponge, чтобы хлебатьвывод первой команды и воссоздание файла обратно с самой последней.

awk '{...}' inventory.txt | sponge inventory.txt

Из вашего образца текста по вопросу, невозможно определить, является ли какой-то язык разметки своего рода (XML, HTML).Если это правильный язык, поддерживающий синтаксис, вам следует использовать синтаксический анализатор, который знает эту грамматику.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...