Как разделять слова кавычками

#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/1

5. @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.