Регулярные выражения в sed: сопоставление символа, которому не предшествует или после которого не указан другой другой символ

Предположим, что неправильно отформатированный фрагмент csv использует точку с запятой в качестве ограничителя поля:

abc;d" "e"f;"ijk"

Согласно RFC4180, кавычка внутри поля должна быть представлена ​​двумя кавычками:

abc;d"" ""e""f;"ijk"

Я пытался добиться этого с помощью sed script that matches any dquote not preceeded or followed by the field terminator (here ;):

echo 'abc;d" "e"f;"ijk"' | sed -e 's/\([^;]\)"\([^;]\)/\1""\2/g'

The result is almost good:

abc;d"" "e""f;"ijk"

except the double quote before the e is not matched and therefore not duplicated.

Can anyone explain me why this doesn't work, since before and after the e there's no semicolon.

1 ответ

Решение

Ваша вторая цитата не соответствует, потому что совпадение будет space quote eи space уже потреблено предыдущим d quote space,

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

У Perl есть подходящее совпадение, которое (немного) легче для глаз:

$ echo 'abc;d" "e"f;"ijk"' | perl -pe 's/(?<!;)"(?![;\n])/""/'g
abc;d"" ""e""f;"ijk"

Перевод: цитата, которой не предшествует регулярное выражение ;, а не регулярное выражение [;\n],

\ N присутствует, потому что perl считает его частью строки и поэтому будет соответствовать последней кавычке, если мы не запретим это.

Другие вопросы по тегам