Как я могу заменить все экземпляры символа между N-м и K-м экземпляром этого символа? - PullRequest
0 голосов
/ 13 июня 2019

Я работаю с большим количеством CSV-файлов, и в одном из столбцов само поле содержит запятые.К сожалению, этот столбец не был заключен в кавычки, поэтому он вызывает проблему с загрузкой файлов CSV во внешние приложения.

Мои файлы CSV выглядят так:

col1, col2, col3, co,,,l4, col5, col6
col1, col2, col3, co,,,,,l4, col5, col6
col1, col2, col3, co,,l4, col5, col6

Мне нужноудалить все запятые в этом конкретном столбце, но я не уверен, как это сделать.К сожалению, переписать файлы с проблемным столбцом, должным образом заключенным в кавычки, не вариант.

Эти проблемные запятые всегда происходят между третьей и второй запятой, но я неу меня достаточно ноу-хау bash для написания сценария, который их удаляет.

Входной файл:

col1, col2, col3, co,,,l4, col5, col6
col1, col2, col3, co,,,,,l4, col5, col6
col1, col2, col3, co,,l4, col5, col6

Ожидаемый результат:

col1, col2, col3, col4, col5, col6
col1, col2, col3, col4, col5, col6
col1, col2, col3, col4, col5, col6

Ответы [ 2 ]

0 голосов
/ 13 июня 2019

Если вы ДЕЙСТВИТЕЛЬНО просто хотите удалить запятые в этом поле, тогда с помощью GNU awk для 3-го аргумента для match ():

awk 'match($0,/(([^,]*,){3})(.*)((,[^,]*){2})/,a){gsub(/,/,"",a[3]); $0=a[1] a[3] a[4]} 1' file
col1, col2, col3, col4, col5, col6
col1, col2, col3, col4, col5, col6
col1, col2, col3, col4, col5, col6

но в противном случае я бы просто обернул проблемное поле в двойные кавычки, а затем обработал его как любой другой CSV (например, см. Какой самый надежный способ эффективного анализа CSV с помощью awk? ):

$ awk 'match($0,/(([^,]*,){3})(.*)((,[^,]*){2})/,a){$0=a[1] "\"" a[3] "\"" a[4]} 1' file
col1, col2, col3," co,,,l4", col5, col6
col1, col2, col3," co,,,,,l4", col5, col6
col1, col2, col3," co,,l4", col5, col6

$ awk '
    BEGIN { FPAT="[^,]*|\"[^\"]+\"" }
    match($0,/(([^,]*,){3})(.*)((,[^,]*){2})/,a) { $0=a[1] "\"" a[3] "\"" a[4] }
    { for (i=1; i<=NF; i++) print NR, NF, i, $i }
' file
1 6 1 col1
1 6 2  col2
1 6 3  col3
1 6 4 " co,,,l4"
1 6 5  col5
1 6 6  col6
2 6 1 col1
2 6 2  col2
2 6 3  col3
2 6 4 " co,,,,,l4"
2 6 5  col5
2 6 6  col6
3 6 1 col1
3 6 2  col2
3 6 3  col3
3 6 4 " co,,l4"
3 6 5  col5
3 6 6  col6

или просто сделать цитату с помощью sed:

$ sed -E 's/(([^,]*,){3})(.*)((,[^,]*){2})/\1"\3"\4/' file
col1, col2, col3," co,,,l4", col5, col6
col1, col2, col3," co,,,,,l4", col5, col6
col1, col2, col3," co,,l4", col5, col6

Выше требуется GNU или BSD / OSX sed для -E. С любым POSIX sed это будет:

$ sed 's/\(\([^,]*,\)\{3\}\)\(.*\)\(\(,[^,]*\)\{2\}\)/\1"\3"\4/' file
col1, col2, col3," co,,,l4", col5, col6
col1, col2, col3," co,,,,,l4", col5, col6
col1, col2, col3," co,,l4", col5, col6
0 голосов
/ 13 июня 2019

Я хотел бы сделать следующее предложение:

awk '{ match($0,/^[^,]*,[^,]*,[^,],/); p1=RLENGTH+1
       match($0,/,[^,]*,[^,]*$/);    ; p2=RSTART
       s=substr($0,p1,p2-p1); gsub(/,/,"",s)
       print substr($0,1,p1-1) s substr($0,p2)
     }' file.csv

или

awk 'BEGIN{FS=OFS=","}
     { s=""; for(i=4;i<NF-1;++i) s=s $i }
     { print $1,$2,$3,s,$(NF-1),$NF }' file.csv

В этих решениях предполагается, что , не появляется в столбцах col1, col2, col3, col5 и col6.

Если у вас есть запятая в других столбцах, но эти столбцы правильно указаны в соответствии со стандартом CSV, то вы можете использовать аналогичный метод на основе Какой самый надежный способ эффективного анализа CSV с помощьюawk?

awk -v FPAT='[^,]*|"[^"]+"' 'BEGIN{OFS=","}
     { s=""; for(i=4;i<NF-1;++i) s=s $i }
     { print $1,$2,$3,s,$(NF-1),$NF }' file.csv

В общих чертах, чтобы ответить на заглавный вопрос:

Как я могу заменить все вхождения символа между N-м и K-м последнимиэкземпляр этого символа?

Предположим, c это символ:

awk 'BEGIN{FS=OFS="c"; n=3; k=}
     { s=""; for(i=1; i <= n   ;++i) s = $i OFS 
             for(   ; i <= NF-k;++i) s=s $i 
             for(   ; i <= NF  ;++i) s = OFS $i }
     { print s }' file.csv
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...