Обтекание поля в строке с переменным числом разделителей - PullRequest
1 голос
/ 02 августа 2010

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

Некоторые строки правильны с 16 разделителями и, следовательно, с 16 полями, в то время как некоторые из строк имеют 18 разделителей только для 16 полей. Мне нужно обернуть 10-е поле кавычками только в том случае, если в нем 18 разделителей вместо 16. У меня есть окно Linux с awk, sed, grep и т. Д., И я хотел бы иметь способ написать это, поэтому я не буду не нужно делать это вручную.

Упрощенный пример ввода / вывода только с 5 и 7 разделителями (в кавычках 4-е поле) будет:

# Input

Field 1|Field 2|Field 3|Field 4|Field 5|Field 6
Field 1|Field 2|Field 3|Field | with | pipes|Field 5|Field 6

# Output

Field 1|Field 2|Field 3|Field 4|Field 5|Field 6
Field 1|Field 2|Field 3|"Field | with | pipes"|Field 5|Field 6

# Optional output if it is easier

Field 1|Field 2|Field 3|"Field 4"|Field 5|Field 6
Field 1|Field 2|Field 3|"Field | with | pipes"|Field 5|Field 6

Любая помощь будет чрезвычайно цениться!

Ответы [ 2 ]

1 голос
/ 03 августа 2010

ПОЦЕЛУЙ. Когда вы работаете с различными полями и разделителями полей, используйте такой инструмент, как awk, который полностью предназначен для работы.

$ cat file
Field 1|Field 2|Field 3|Field 4|Field 5|Field 6
Field 1|Field 2|Field 3|Field | with | pipes|Field 5|Field 6

$ awk -F"|" 'NF>6{$4="\042"$4 ; $(NF-2)=$(NF-2)"\042";}1' OFS="|"  file
Field 1|Field 2|Field 3|Field 4|Field 5|Field 6
Field 1|Field 2|Field 3|"Field | with | pipes"|Field 5|Field 6

выше сказано, что если количество полей больше 6 (то есть NF> 6), то добавьте двойную кавычку (\ 042) к 4-му полю, а также к последнему 2-му полю. (или измените его соответствующим образом в зависимости от ваших данных.)

Нет необходимости использовать сложное регулярное выражение.

1 голос
/ 02 августа 2010

Для ваших образцов данных:

sed -i '/\([^|]*|\)\{7\}/{s/\([^|]*|\)/"\1/4;s/\(|[^|]*\)/"\1/6}' inputfile

Для ваших реальных данных:

sed -i '/\([^|]*|\)\{17\}/{s/\([^|]*|\)/"\1/14;s/\(|[^|]*\)/"\1/16}' inputfile

Редактировать:

(я добавил парупропущенных фигурных скобок в каждом примере, поэтому вторая команда s (фактически обе) работает только при совпадении адреса. Я также удалил -n и p. Удаление p устраняет дублирование. Извините за ошибки.)

Часть перед командой s называется "адресом".Он выбирает только те строки, которые имеют 7 (или 17) символов канала, что исключает использование команды s для строк с другим количеством символов канала.

  • // - Разделители дляадрес
  • \(\) - групповые скобки (экранированные)
  • [^|]* - ноль или более (*) непотоковых (^|) символов ([] - символсписок разделителей)
  • | - и интересующий нас символ канала
  • \{7\} - повторить группу семь раз
  • {command; command} - эти скобки разделяютблок команд, который будет выполняться при сопоставлении адреса - вместе адрес и фигурные скобки действуют как оператор if и связанный с ним блок

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

Тогда первая команда s говорит о замене 4-го (или 14-го) символа канала и его предшествующих символов, не являющихся каналами, кавычкой, за которой следуют соответствующие символы.

Точка с запятой является разделителем команд.Некоторые версии sed требуют, чтобы вместо точек с запятой вы использовали форму `sed -e 'command' -e 'command' для однокомпонентных сценариев с несколькими командами.

Кстати, sэто команда, а не часть регулярного выражения.Часть между начальной парой слешей в командах выше и часть между начальной парой слешей в команде s/// являются регулярными выражениями.

Пожалуйста, дайте мне знать, если у вас есть дополнительные вопросы.Вторая команда s ищет 6-й (или 16-й) символ канала и ноль или более непузырьков, следующих за ним, и заменяет его на себя (совпавшие символы) и кавычку.

...