Как заменить текст с помощью sed или awk? - PullRequest
4 голосов
/ 06 августа 2010

У меня есть следующий файл json:

 { "last_modified": {
         "type": "/type/datetime", 
         "value": "2008-04-01T03:28:50.625462" }, 
     "type": { "key": "/type/author" }, 
     "name": "National Research Council. Committee on the Scientific and Technologic Base of Puerto Rico"s Economy.", 
     "key": "/authors/OL2108538A", 
     "revision": 1 }

Значение name имеет двойную кавычку, и я хочу заменить эту двойную кавычку только одинарной (не любой другой двойной кавычкой) Как я могу это сделать?

Ответы [ 7 ]

3 голосов
/ 06 августа 2010

Если вы хотите переопределить все вхождения одного символа, вы также можете использовать команду tr, более простую, чем sed или awk:

   cat myfile.txt | tr \" \'

Обратите внимание, что обе кавычки экранированы. Если у вас есть другие символы, кроме кавычек, просто напишите:

   cat myfile.txt | tr a A

Редактировать: обратите внимание, что после того, как вопрос был отредактирован, этот ответ больше не действителен: он заменяет все двойные кавычки, а не только одну в свойстве Name.

1 голос
/ 06 августа 2010

Добавление некоторых других странных ошибок в ваш ввод

{ "last_modified": {"type": "/type/datetime", "value": "2008-04-01T03:28:50.625462"},
  "type": {"key": "/type/author"},
  "name": "National Research Council. Committee on the Scientific and Technologic Base of Puerto Rico"s Economy.",
  "key": "/authors/OL2108538A",
  "revision": 1,
  "has \" escaped quote": 1,
  "has \" escaped quotes \"": 1,
  "has multiple " internal " quotes": 1,
}

этой Perl-программы, которая исправляет неэкранированные внутренние двойные кавычки, используя эвристику, что фактическая заключительная кавычка строки сопровождается необязательнойПробел и двоеточие, запятая, точка с запятой или фигурная скобка

#! /usr/bin/perl -p

s<"(.+?)"(\s*[:,;}])> {
  my($text,$terminator) = ($1,$2);
  $text =~ s/(?<!\\)"/'/g;  # " oh, the irony!
  qq["$text"] . $terminator;
}eg;

производит следующий вывод:

$ ./fixdqs input.json
{ "last_modified": {"type": "/type/datetime", "value": "2008-04-01T03:28:50.625462"},
  "type": {"key": "/type/author"},
  "name": "National Research Council. Committee on the Scientific and Technologic Base of Puerto Rico's Economy.",
  "key": "/authors/OL2108538A",
  "revision": 1,
  "has \" escaped quote": 1,
  "has \" escaped quotes \"": 1,
  "has multiple ' internal ' quotes": 1,
}

Дельта от ввода к выводу:

$ diff -ub input.json <(./fixdqs input.json)
--- input.json
+++ /dev/fd/63
@@ -1,9 +1,9 @@
 { "last_modified": {"type": "/type/datetime", "value": "2008-04-01T03:28:50.625462"},
   "type": {"key": "/type/author"},
-  "name": "National Research Council. Committee on the Scientific and Technologic Base of Puerto Rico"s Economy.",
+  "name": "National Research Council. Committee on the Scientific and Technologic Base of Puerto Rico's Economy.",
   "key": "/authors/OL2108538A",
   "revision": 1,
   "has \" escaped quote": 1,
   "has \" escaped quotes \"": 1,
-  "has multiple " internal " quotes": 1,
+  "has multiple ' internal ' quotes": 1,
 }
1 голос
/ 06 августа 2010

Я думаю, что было бы лучше использовать sed примерно так:

sed 's / "/' / g 'ваш файл

0 голосов
/ 16 мая 2013

Если только кавычки вокруг «имени», то вы можете использовать sed из командной строки или в bash-скрипте:

    sed -i 's/ "name"/ '\'name\''/g' filename.json

Протестировано, работает.

0 голосов
/ 06 августа 2010
awk '{for(i=1;i<=NF;i++) if($i~/name/) { gsub("\042","\047",$(i+1)) }   }1' file
0 голосов
/ 06 августа 2010

Предположим, что ваши данные в точности соответствуют вашим показаниям, а лишние двойные кавычки появляются только в поле значения имени:

Обновление:

Я сделал скрипт немного более устойчивым (обработка ',' внутри полей).

BEGIN {
    q = "\""
    FS = OFS = q ", " q
}
{
    split($1, arr, ": " q)
    gsub(q, "'", arr[2])
    print arr[1] ": " q arr[2], $2, $3
}

Поместите этот скрипт в файл (скажем, dequote.awk) и запустите скрипт с
awk -f dequote.awk input.json > output.json.

Обновление 2:

Хорошо, поэтому ваш ввод данных чрезвычайно сложно обработать. Единственное, о чем я могу думать, это следующее:

{
    start = match($0, "\"name\": ") + 8
    stop = match($0, "\", \"key\": ")
    if (start == 8 || stop == 0) {
        print
        next
    }
    pre = substr($0, 1, start)
    post = substr($0, stop)
    name = substr($0, start + 1, stop - start - 1)
    gsub("\"", "'", name)
    print pre name post
}

Объяснение: Я пытаюсь разделить строку на три части:

  1. До первой двойной кавычки для поля значения "имя";
  2. поле значения "имя" минус двойные кавычки;
  3. закрывающая двойная кавычка и остальная часть строки.

Во второй части я заменяю все двойные кавычки одинарными. Затем я склеиваю эти три части вместе и печатаю их.

0 голосов
/ 06 августа 2010

Если вы имеете в виду просто двойную кавычку в 'Rico"s', вы можете использовать:

sed "s/Rico\"s/Rico's/"

как в:

pax> echo '{"name": "National Res...rto Rico"s Economy.", "key": "blah"}'
     | sed "s/Rico\"s/Rico's/"
{"name": "National Res...rto Rico's Economy.", "key": "blah"}
...