2

I've got problem to replace " to \" and \ to \\ and except " of json

test.txt input file

"a"     "b"     
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\uff08\u524d\u5bfe\u5fdc

I want to output like

\"a\"     \"b\"     
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\\uff08\\u524d\\u5bfe\\u5fdc
  • 1
    How complex is your file? Will the JSON string always be in a single line? Will the JSON string never contain { or }? Will there be multiple lines of data? Will the JSON data always be the only line(s) in the file that start with a {? – terdon Apr 9 at 11:34
  • the data like this bro. ``` "a","b",{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"},\uff08\u524d\u5bfe\u5fdc ``` – JOIN MAX Apr 10 at 4:59
5

To be more robust, you could do a full json parsing:

perl -0777 -pe '
  s@(".*?"|\\)|(\{(?:"(?:\\.|[^"])*+"|(?2)|[^"{}]++)*+\})|[^{}\\"]+@
  $1 ? $1 =~ s/["\\]/\\$&/gr : $&@gse'

Which on an input like

"a"     "b"     "c{d"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
{
  "1": {"x": "y"}
  "2": "}}}"
  "3": ["{\"x", "}"]
}
\uff08\u524d\u5bfe\u5fdc

gives

\"a\"     \"b\"     \"c{d\"
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
{
  "1": {"x": "y"}
  "2": "}}}"
  "3": ["{\"x", "}"]
}
\\uff08\\u524d\\u5bfe\\u5fdc

You may want to clarify what you want to do if the input contains "foo\"bar" or "foo\nbar" outside of json objects.

  • Thanks you for saved my times – JOIN MAX Apr 10 at 1:45
  • how about all data in one line? like this "a","b",{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"},\uff08\u524d\u5bfe\u5fdc – JOIN MAX Apr 10 at 4:57
  • @JOINMAX, how about it? The code above should change it to \"a\",\"b\",{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"},\\uff08\\u524d\\u5bfe\\u5fdc, is it not what you want? – Stéphane Chazelas Apr 10 at 21:37
3

In the simple example you show, this is easy. Just escape the characters only on lines that don't start with a {:

$ sed -E '/^[^{]/s|(["\])|\\\1|g' file 
\"a\"     \"b\"     
{"1":"female","2":"197312","3":"359","4":"201109","5":"mail"}
\\uff08\\u524d\\u5bfe\\u5fdc

However, things get considerably more complicated if your JSON can span several lines. For such cases, you can write a little script that counts the number of opening { and closing } and only applies the replacement while those numbers are equal (so when we aren't in a JSON string). Something like:

perl -F'' -ne 'for (@F){$op++ if /{/; $cl++ if /}/; if($cl==$op){s|["\\]|\\$&|g;}print}' file 

However, this will also break if the JSON string itself can contain { or } which don't signify a JSON section (e.g. {"1":"b-{c}"} or whatever). For such cases, use Stéphane's approach instead.

  • Thanks you for saved my times – JOIN MAX Apr 10 at 1:45
0
$ sed 's/\(\\\|^"\|"$\|"[ \t]\)/\\\1/g' test.txt | sed 's/\([ \t]\)"/\1\\"/g'
  • Replace \ or " at start of line or end of line or before space/tab character:
    's/\(\\\|^"\|"$\|"[ \t]\)/\\\1/g'
  • or " after space/tab character: sed 's/\([ \t]\)"/\1\\"/g'

So this only works if your json string doesn't contain any space/tab characters and is on one line.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.