Как вы считаете и заменяете строку в текстовом файле, которая начинается в конце одной строки и продолжается в следующей с помощью команд linux? - PullRequest
0 голосов
/ 09 мая 2018

У меня большой (4 ГБ) текстовый файл Windows .csv (каждая строка заканчивается на «\ r \ n») в среде Linux, который должен был быть файлом с разделителями csv (delimiter = '|', текст qualifier = '"') с каждым полем, разделенным трубкой и заключенным в двойные кавычки. Предполагалось, что в любом текстовом поле с внедренными двойными кавычками двойная кавычка должна экранироваться со второй двойной кавычкой (т. е." быстрая "коричневая" лиса "должен был быть представлен как" быстрый "" коричневый "" лис "). К сожалению, экранирования двойных кавычек не произошло. Кроме того, текстовые поля могут включать в себя новые строки (например, Windows CR (\ r \ n)) которые должны быть сохранены.

Пример строки может выглядеть следующим образом:

"1234567890123456"|"2016-07-30"|"2016-08-01"|"123"|"456"|"789"|"text narrative field starts\r\n
with text lines that may have embedded double quotes "For example"\r\n
and may include measurements such as 1/2" x 2" with \r\n
the text continuing and includes embedded line breaks \r\n
which will finally be terminated with a double quote"\r\n
"9876543210654321"|"2017-01-31"|"2018-08-01"|"123"|"456"|"789"|"text narrative field"\r\n
"2345678901234567"|"...."\r\n

с целью сделать вывод следующим образом:

~1234567890123456~|~2016-07-30~|~2016-08-01~|~123~|~456~|~789~|~text narrative field starts\r\n
with text lines that may have embedded double quotes ""For example""\r\n
and may include measurements such as 1/2"" x 2"" with \r\n
the text continuing and includes embedded line breaks \r\n
which will finally be terminated with a double quote~\r\n
~9876543210654321~|~2017-01-31~|~2018-08-01~|~123~|~456~|~789~|~text narrative field~\r\n
~2345678901234567~|~....~\r\n

Я пытался реализовать решение:

  1. УСПЕШНО: измените все "|" последовательности к ~ | ~

  2. УСПЕШНО: замените двойную кавычку (") в начале первой строки и конце последней строки на тильду (~)

  3. изменить заканчивающиеся и начальные двойные кавычки на тильды для любых строк, заканчивающихся двойными кавычками в конце первой строки и заканчивающихся символом CR (\ r \ n) (например, ... "\ r \ n) и следующая строка начинается с двойной кавычки, за которой следуют 16-значный номер и тильда (например, "1234567890123456 ~ ...) (т. е. это начало новой записи)

  4. преобразовать все оставшиеся двойные кавычки в две последовательные двойные кавычки (изменить "на" ")

  5. затем переверните первые 3 шага выше, изменив все ~ обратно на двойные кавычки.

Я начал с использования sed, чтобы заменить все строки на двойные кавычки, за которыми следовала труба, а затем двойные кавычки (т. Е. "|") На тильду, трубу, тильду (т.е. ~ | ~). Затем я вручную заменил первую и последнюю двойную кавычку в файле тильдой.

Здесь я столкнулся с проблемами, пытаясь подсчитать количество случаев, когда строка заканчивается двойной кавычкой ("), а начало следующей строки начинается с двойной кавычки, за которой следуют 16-значное число и" ~ "который скажет мне фактическое количество записей CSV в файле (минус одна), а не количество строк. Я попытался сделать это с помощью grep: grep '"\r\n"\d{16}~' | wc -l, но это не сработало

Затем мне нужно заменить те двойные кавычки, в которых двойная кавычка заканчивает запись, а последующая запись начинается с двойной кавычки, за которой следуют 16-значное число и «~», оставляя все остальное нетронутым.

Я пытался использовать sed: sed 's/"\r\n"(\d{16}~)/~\r\n~\1' windows_file.txt, но он не работает, как хотелось бы.

Буду признателен за любые рекомендации относительно того, как выполнить вышеуказанное.

1 Ответ

0 голосов
/ 10 мая 2018

Сценарий ниже делает то, что вы ожидаете, используя awk, за исключением самой последней строки в файле, так как он не знает, где заканчивается эта запись. Это может быть исправлено путем подсчета строк в файле, но это будет непрактично, поскольку это большой файл. Глядя на структуру данных, записи разделяются "\r\n", а поля "|", давайте использовать это с awk.

gawk 'BEGIN{ 
    RS="\"\r\n\""  # input record separator RS, 2 double quotes with a DOS line ending in the middle
    FS="\"\\|\""   # input field separator FS, 2 double quotes with a pipe in the middle
    ORS="~\r\n~"   # your record separator
    OFS="~|~"      # your field separator
} {
    $1=$1 # trick awk into believing something has changed
    if (NR == 1){  # first record, replace first character
        print "~" substr($0,2) 
    }else{
        print $0
    } 
} ' test.txt

Результат (при условии, что строки заканчиваются на \ r \ n):

~1234567890123456~|~2016-07-30~|~2016-08-01~|~123~|~456~|~789~|~text narrative field starts
with text lines that may have embedded double quotes "For example"
and may include measurements such as 1/2" x 2" with 
the text continuing and includes embedded line breaks 
which will finally be terminated with a double quote~
~9876543210654321~|~2017-01-31~|~2018-08-01~|~123~|~456~|~789~|~text narrative field~
~10654321~|~2018-09-31~|~2018-08-01~|~123~|~456~|~789~|~asdasdasdasdad asasda"
~
~

PS: прервется, если поле содержит строку, которая начинается с ", а предыдущая строка в том же конце заканчивается "\r\n, поскольку шаблон будет соответствовать предлагаемому RS.

"10654321"|"2018-09-31"|"2018-08-01"|"123"|"456"|"789"|"asdasdasdasdad asasda"\r\n
"some more"\r\n
"22222"|".... (another record)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...