#awk #sed #command-line
#awk #sed #командная строка
Вопрос:
Я работаю над набором данных автомобилей; марка и модель автомобилей отображаются в строке, как показано ниже. Вы можете предположить, что модель состоит только из одного слова.
"Honda civic LX"
"audi 500s (diesel)"
"toyota camry"
"ford ranger"
Мой желаемый результат — иметь make (который состоит из одного слова) в одинарных кавычках, в то время как model и trim заключены в собственные одинарные кавычки, как показано ниже:
'honda' 'civic LX'
'audi' '500s (diesel)'
'toyota' 'camry'
'ford' 'ranger'
Я должен также отметить, что набор данных, с которым я работаю, организован как таковой.
28.0 4 119 82.0 2720 99 1 "audi 500s (diesel)"
23.5 4 225 76.0 5530 81 1 "toyota camry"
Я хочу решить эту проблему с помощью SED, и я приблизился к ее решению с помощью следующей команды.
sed "s/"/'/g;s/ /' '/"
Однако это делает мой набор данных похожим на приведенный ниже. Вы можете видеть, что он добавляет ‘ ‘ в конце первого столбца, что не то, что я хочу. Кроме того, я думал, что команда будет разделять make и model, но это не так.
28.0' ' 4 119 82.0 2720 99 1 'audi 500s (diesel)'
23.5' ' 4 225 76.0 5530 81 1 'toyota camry'
Комментарии:
1.
sed -E 's/"([^" ] ) ([^"] )"$/'"'1' '2'/"
2.
awk -F" -v q=' '{sub(/ /,q" "q,$2);$2=q$2q}1'
3. @jhnc Спасибо! Вы не возражаете против разбиения команды SED?
4. Кроме слегка загадочного экранирования для одинарных / двойных кавычек, это всего лишь простая
s///
команда. Смотрите: regex101.com/r/pMjctB/15. @jhnc Огромное спасибо. предоставленная вами ссылка действительно полезна, и я обязательно буду использовать ее в будущем!
Ответ №1:
Надеюсь, это сработает.
sed "s/"/'/g"| sed -E "s/([a-z])( )/1' '/"
Объяснение
Первая часть (или часть «найти») ([a-z])( )
находит вхождение алфавита в нижнем регистре, за которым следует пробел, в 2 группы, которые обозначаются символом ()
. Итак, первая группа — это алфавит ([a-z])
, а вторая группа — пробел ( )
.
Во второй части (или части замены) 1' '
1
обозначает первую найденную группу (это обратная ссылка, и для ее работы необходим флаг -E). Если мы этого не сделали, алфавит и пробел будут заменены на ' '
, поэтому мы потеряем последний алфавит, что приведет к чему-то вроде aud' '500s (diesel)'
. Чтобы сохранить последний алфавит, мне пришлось это сделать.
Комментарии:
1. Спасибо, это очень помогло. Вы не против разбить второе выражение? «sed -E «s/([a-z])( )/1′ ‘/» »
Ответ №2:
Я бы остановился awk
на этом (что дает нам больше простоты с точки зрения функций и их использования), если вы согласны с этим. Не могли бы вы, пожалуйста, попробовать следующее, написанное и протестированное с показанными примерами в GNU awk
.
awk -v s1="47" '
match($0,/"[^"]*"/){
if(RSTART>1){
printf("%s ",substr($0,1,RSTART-1))
}
matched=substr($0,RSTART,RLENGTH)
num=split(matched,arr," ")
for(i=1;i<=num;i ){
gsub(/"/,"",arr[i])
val=(val?val OFS:"") (s1 arr[i] s1)
}
printf("%s%sn",val,(RSTART RLENGTH)<length($0)?substr($0,RSTART RLENGTH 1):"")
val=""
}
' Input_file
Объяснение: добавление подробного объяснения выше.
awk -v s1="47" ' ##Starting awk program from here and creating variable s1 which has single quote in it as a value.
match($0,/"[^"]*"/){ ##Using match function to match from " to till " here.
if(RSTART>1){ ##If RSTART is greater than 1 then do following.
printf("%s ",substr($0,1,RSTART-1)) ##Printing string sub string of current line from 1 to RSTART-1 here.
}
matched=substr($0,RSTART,RLENGTH) ##Creating matched variable which has regex matched value here.
num=split(matched,arr," ") ##Splitting matched into arr with delimiter of space.
for(i=1;i<=num;i ){ ##Running a loop from i=1 to till num value which has number of elements in arr value in it(taken above).
gsub(/"/,"",arr[i]) ##Globally substituting " with NULL in arr value here.
val=(val?val OFS:"") (s1 arr[i] s1) ##Creating val which has current value of arr wrapped in s1 and keep appending its value to it.
}
printf("%s%sn",val,((RSTART RLENGTH)<length($0)?substr($0,RSTART RLENGTH 1):"")) ##Printing val and rest of line here.
val="" ##Nullifying val here.
}
' Input_file ##Mentioning Input_file name here.