Регулярное выражение в несколько строк
Я застрял с этим в течение нескольких часов и перебрал множество различных инструментов, чтобы выполнить работу. Безуспешно. Было бы замечательно, если бы кто-то мог помочь мне с этим.
Вот проблема:
У меня очень большой файл CSV (400mb+), который отформатирован неправильно. Прямо сейчас это выглядит примерно так:
This is a long abstract describing something. What follows is the tile for this sentence."
,Title1
This is another sentence that is running on one line. On the next line you can find the title.
,Title2
Как вы, вероятно, видите, заголовки ", Title1" и ", Title2" должны находиться в той же строке, что и предыдущее предложение. Тогда это будет выглядеть примерно так:
This is a long abstract describing something. What follows is the tile for this sentence.",Title1
This is another sentence that is running on one line. On the next line you can find the title.,Title2
Обратите внимание, что конец предложения может содержать кавычки или нет. В конце они тоже должны быть заменены.
Вот что я придумала:
sed -n '1h;1!H;${;g;s/\."?.*,//g;p;}' out.csv > out1.csv
Это должно фактически выполнить работу по сопоставлению выражения по нескольким строкам. К сожалению это не так :)
Выражение ищет точку в конце предложения и дополнительные кавычки плюс символ новой строки, с которым я пытаюсь сопоставить. *.
Помощь высоко ценится. И не имеет значения, какой инструмент выполняет работу (awk, perl, sed, tr и т.д.).
Ответы
Ответ 1
Многострочный в sed
не всегда является сложным как таковым, он просто использует команды, большинство из которых не знакомы и имеют определенные побочные эффекты, такие как разделение текущей строки со следующей строки на "\n" когда вы используете "N" для добавления следующей строки в пространство шаблонов.
Во всяком случае, это намного проще, если вы соглашаетесь на строку, начинающуюся с запятой, чтобы решить, удалять ли новую строку, чтобы я здесь:
sed 'N;/\n,/s/"\? *\n//;P;D' title_csv
Ввод
$ cat title_csv
don't touch this line
don't touch this line either
This is a long abstract describing something. What follows is the tile for this sentence."
,Title1
seriously, don't touch this line
This is another sentence that is running on one line. On the next line you can find the title.
,Title2
also, don't touch this line
Выход
$ sed 'N;/\n,/s/"\? *\n//;P;D' title_csv
don't touch this line
don't touch this line either
This is a long abstract describing something. What follows is the tile for this sentence.,Title1
seriously, don't touch this line
This is another sentence that is running on one line. On the next line you can find the title.,Title2
also, don't touch this line
Ответ 2
Работает с несколькими небольшими изменениями:
sed -n '1h;1!H;${;g;s/\."\?\n,//g;p;}' inputfile
?
должен быть экранирован, а .
не соответствует символам новой строки.
Вот еще один способ сделать это, который не требует использования пространства удержания:
sed -n '${p;q};N;/\n,/{s/"\?\n//p;b};P;D' inputfile
Вот прокомментированная версия:
sed -n '
$ # for the last input line
{
p; # print
q # and quit
};
N; # otherwise, append the next line
/\n,/ # if it starts with a comma
{
s/"\?\n//p; # delete an optional comma and the newline and print the result
b # branch to the end to read the next line
};
P; # it doesn't start with a comma so print it
D # delete the first line of the pair (it just been printed) and loop to the top
' inputfile