Bagaimana cara menangani baris baru di JSON?


289

Saya telah menghasilkan beberapa JSON dan saya mencoba menariknya ke dalam objek di JavaScript. Saya terus mendapatkan kesalahan. Inilah yang saya miliki:

var data = '{"count" : 1, "stack" : "sometext\n\n"}';
var dataObj = eval('('+data+')');

Ini memberi saya kesalahan:

unterminated string literal

Dengan JSON.parse(data), saya melihat pesan kesalahan serupa: "Unexpected token ↵ " di Chrome, dan " unterminated string literal" di Firefox dan IE.

Ketika saya mengambil \nsetelah sometextkesalahan hilang dalam kedua kasus. Saya tidak bisa mencari tahu mengapa hal itu \nmembuat evaldan JSON.parsegagal.


19
Coba gunakan parser json nyata, bukan eval.
Eric

Jawaban:


368

Saya kira inilah yang Anda inginkan:

var data = '{"count" : 1, "stack" : "sometext\\n\\n"}';

(Anda harus keluar dari "\" di string Anda (mengubahnya menjadi dobel - "\"), jika tidak, ia akan menjadi baris baru di sumber JSON, bukan data JSON.)


101
Ini tentu saja benar, tetapi saya ingin menambahkan alasan karena harus melakukan ini: spesifikasi JSON di ietf.org/rfc/rfc4627.txt berisi kalimat ini di bagian 2.5: "Semua karakter Unicode dapat ditempatkan di dalam tanda kutip kecuali untuk karakter yang harus diloloskan: tanda kutip, reverse solidus, dan karakter kontrol (U + 0000 hingga U + 001F). " Karena baris baru adalah karakter kontrol, itu harus diloloskan.
daniel kullmann

1
Menurut www.json.org JSON tidak menerima urutan kontrol "\ n" dalam string - dan jika Anda mencoba JSON.parse (['"a \\ na"']) [1] .charCodeAt (); yang akan menampilkan 10 - yang merupakan "Linefeed" terakhir kali saya periksa. --- BTW: Berhenti berteriak!
BlaM

+ 1. Saya mengalami kesulitan memahami pengkodean JSON tetapi "akan menjadi baris baru di sumber JSON, bukan data JSON" membuatnya menjadi jelas bagi saya.
amucunguzi

44

Anda akan perlu memiliki fungsi yang menggantikan \nuntuk\\n dalam kasus dataini tidak literal string yang.

function jsonEscape(str)  {
    return str.replace(/\n/g, "\\\\n").replace(/\r/g, "\\\\r").replace(/\t/g, "\\\\t");
}

var data = '{"count" : 1, "stack" : "sometext\n\n"}';
var dataObj = JSON.parse(jsonEscape(data));

Hasilnya dataObjakan

Object {count: 1, stack: "sometext\n\n"}

3
Anda perlu melarikan diri karakter pelarian Anda (yaitu .replace("\\n", "\\\\n")) dan saya juga akan menyarankan menggunakan regex untuk memungkinkan mengganti beberapa instance (yaitu .replace(/\n/g, "\\\\n"))
musefan

2
mengapa Anda perlu melarikan diri karakter melarikan diri? Maksud saya sesuatu seperti .replace("\n", "\\n")harus melakukan pekerjaan dengan baik !! Misalnya, var test = [{"description":"Some description about the product. This can be multi-line text."}]; console.log(JSON.parse(test.replace(/\n/g, "\\n")));akan menampilkan objek dengan sangat baik ke konsol peramban sebagai[{"description":"Some description about the product.\nThis can be multi-line text."}]
Fr0zenFyr

BTW, dalam komentar di atas, string JSON asli memiliki baris baru, yang dihapus oleh formatter komentar stackoverflow .. Anda dapat melihat bahwa hasil akhir setelah penggantian harus memasukkan karakter baris baru \npada nilai.
Fr0zenFyr

1
-1 Jawaban ini pertama membangun string JSON tidak valid (karena baris baru adalah karakter kontrol), kemudian mencoba memperbaikinya dengan serangkaian penggantian tidak lengkap (ada lebih dari 3 karakter kontrol). Kemudian to top it off, itu juga berhasil menggunakan evalfungsi. 17 suara positif ???
Phil

1
Bagaimana dengan tanda kutip yang perlu diloloskan juga?
berdiri sendiri

8

Menurut spesifikasi, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf :

String adalah urutan titik kode Unicode yang dibungkus dengan tanda kutip ( U+0022). Semua karakter dapat ditempatkan di dalam tanda kutip kecuali untuk karakter yang harus melarikan diri: tanda kutip ( U+0022), membalikkan solidus ( U+005C), dan karakter kontrol U+0000ke U+001F. Ada representasi urutan dua karakter dari beberapa karakter.

Jadi, Anda tidak dapat lulus 0x0Aatau 0x0Ckode secara langsung. Itu dilarang! Spesifikasi menyarankan untuk menggunakan sekuens escape untuk beberapa kode yang didefinisikan dengan baik dari U+0000ke U+001F:

  • \fmewakili karakter umpan formulir ( U+000C).
  • \nmewakili karakter umpan baris ( U+000A).

Karena sebagian besar bahasa pemrograman menggunakan \untuk mengutip, Anda harus menghindari sintaks escape (double-escape - sekali untuk bahasa / platform, satu kali untuk JSON itu sendiri):

jsonStr = "{ \"name\": \"Multi\\nline.\" }";

3

Anda bisa saja melepaskan string Anda di server ketika menulis nilai bidang JSON dan menghapusnya ketika mengambil nilai di browser klien, misalnya.

Implementasi JavaScript dari semua browser utama memiliki perintah unescape.

Contoh:

Di server:

response.write "{""field1"":""" & escape(RS_Temp("textField")) & """}"

Di browser:

document.getElementById("text1").value = unescape(jsonObject.field1)

2

Anda mungkin ingin melihat fungsi C # ini untuk keluar dari string:

http://www.aspcode.net/C-encode-a-string-for-JSON-JavaScript.aspx

public static string Enquote(string s)  
{ 
    if (s == null || s.Length == 0)  
    { 
        return "\"\""; 
    } 
    char         c; 
    int          i; 
    int          len = s.Length; 
    StringBuilder sb = new StringBuilder(len + 4); 
    string       t; 

    sb.Append('"'); 
    for (i = 0; i < len; i += 1)  
    { 
        c = s[i]; 
        if ((c == '\\') || (c == '"') || (c == '>')) 
        { 
            sb.Append('\\'); 
            sb.Append(c); 
        } 
        else if (c == '\b') 
            sb.Append("\\b"); 
        else if (c == '\t') 
            sb.Append("\\t"); 
        else if (c == '\n') 
            sb.Append("\\n"); 
        else if (c == '\f') 
            sb.Append("\\f"); 
        else if (c == '\r') 
            sb.Append("\\r"); 
        else 
        { 
            if (c < ' ')  
            { 
                //t = "000" + Integer.toHexString(c); 
                string t = new string(c,1); 
                t = "000" + int.Parse(tmp,System.Globalization.NumberStyles.HexNumber); 
                sb.Append("\\u" + t.Substring(t.Length - 4)); 
            }  
            else  
            { 
                sb.Append(c); 
            } 
        } 
    } 
    sb.Append('"'); 
    return sb.ToString(); 
} 

3
Mengapa ini lolos >?
nothingisnecessary

0

Saya menggunakan fungsi ini untuk menghapus baris baru atau karakter lain dalam data untuk mem-parsing data JSON:

function normalize_str($str) {

    $invalid = array(
        'Š'=>'S', 'š'=>'s',  'Đ'=>'Dj', 'đ'=>'dj', 'Ž'=>'Z', 'ž'=>'z',
        'Č'=>'C', 'č'=>'c',  'Ć'=>'C',  'ć'=>'c',  'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A',
        'Ä'=>'A', 'Å'=>'A',  'Æ'=>'A',  'Ç'=>'C',  'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E',
        'Ì'=>'I', 'Í'=>'I',  'Î'=>'I',  'Ï'=>'I',  'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O',
        'Õ'=>'O', 'Ö'=>'O',  'Ø'=>'O',  'Ù'=>'U',  'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y',
        'Þ'=>'B', 'ß'=>'Ss', 'à'=>'a',  'á'=>'a',  'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a',
        'æ'=>'a', 'ç'=>'c',  'è'=>'e',  'é'=>'e',  'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i',
        'î'=>'i', 'ï'=>'i',  'ð'=>'o',  'ñ'=>'n',  'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o',
        'ö'=>'o', 'ø'=>'o',  'ù'=>'u',  'ú'=>'u',  'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b',
        'ÿ'=>'y', 'Ŕ'=>'R',  'ŕ'=>'r',
        "`" => "'", "´" => "'",  '"' => ',',  '`' => "'",
        '´' => "'", '"' => '\"', '"' => "\"", '´' => "'",
        "&acirc;€™" => "'",
        "{" => "",
        "~" => "",  "–" => "-",  "'" => "'",  "     " => " ");

    $str = str_replace(array_keys($invalid), array_values($invalid), $str);

    $remove = array("\n", "\r\n", "\r");
    $str = str_replace($remove, "\\n", trim($str));

    //$str = htmlentities($str, ENT_QUOTES);

    return htmlspecialchars($str);
}

echo normalize_str($lst['address']);

9
Di sebagian besar bahasa, Anda memiliki cara yang lebih baik untuk menghilangkan aksen dari string unicode daripada menuliskan fungsi pemetaan Anda sendiri. Lihat pertanyaan ini untuk contoh dalam python: stackoverflow.com/questions/517923/...
MiniQuark

ya kami punya banyak cara untuk mengontrol karakter khusus dalam bahasa yang berbeda.
ShivarajRH

2
Itu semua buruk untuk menelanjangi mereka secara umum. Lebih baik mengkodekan mereka sebagai referensi karakter numerik XML dan kemudian decode pada sisi penerima.
Annarfych

0

JSON.stringify

JSON.stringify(`{ 
  a:"a"
}`)

akan mengonversi string di atas ke

"{ \n      a:\"a\"\n    }"

seperti yang disebutkan di sini

json merangkai

Fungsi ini menambahkan tanda kutip ganda pada awal dan akhir dari string input dan lolos dari karakter JSON khusus. Secara khusus, baris baru diganti oleh karakter \ n, tab digantikan oleh karakter \ t, garis miring terbalik digantikan oleh dua garis miring terbalik \, dan garis miring terbalik ditempatkan sebelum setiap tanda kutip.


4
Ini hanya jawaban kode untuk pertanyaan berumur sebelas tahun dengan delapan jawaban lain yang ada. Berguna untuk menjelaskan kode, dan juga untuk menjelaskan aspek pertanyaan baru apa yang dijawab oleh jawaban Anda, dan jika berlalunya waktu dan rilis versi baru berdampak pada jawaban Anda.
Jason Aller

-1

Saya mengalami masalah saat membuat kelas di PHP 4 untuk meniru json_encode (tersedia dalam PHP 5). Inilah yang saya pikirkan:

class jsonResponse {
    var $response;

    function jsonResponse() {
        $this->response = array('isOK'=>'KO', 'msg'=>'Undefined');
    }

    function set($isOK, $msg) {
        $this->response['isOK'] = ($isOK) ? 'OK' : 'KO';
        $this->response['msg'] = htmlentities($msg);
    }

    function setData($data=null) {
        if(!is_null($data))
            $this->response['data'] = $data;
        elseif(isset($this->response['data']))
            unset($this->response['data']);
    }

    function send() {
        header('Content-type: application/json');
        echo '{"isOK":"' . $this->response['isOK'] . '","msg":' . $this->parseString($this->response['msg']);
        if(isset($this->response['data']))
            echo ',"data":' . $this->parseData($this->response['data']);
        echo '}';
    }

    function parseData($data) {
        if(is_array($data)) {
            $parsed = array();
            foreach ($data as $key=>$value)
                array_push($parsed, $this->parseString($key) . ':' . $this->parseData($value));
            return '{' . implode(',', $parsed) . '}';
        }
        else
            return $this->parseString($data);
    }

    function parseString($string) {
            $string = str_replace("\\", "\\\\", $string);
            $string = str_replace('/', "\\/", $string);
            $string = str_replace('"', "\\".'"', $string);
            $string = str_replace("\b", "\\b", $string);
            $string = str_replace("\t", "\\t", $string);
            $string = str_replace("\n", "\\n", $string);
            $string = str_replace("\f", "\\f", $string);
            $string = str_replace("\r", "\\r", $string);
            $string = str_replace("\u", "\\u", $string);
            return '"'.$string.'"';
    }
}

Saya mengikuti aturan yang disebutkan di sini . Saya hanya menggunakan apa yang saya butuhkan, tetapi saya pikir Anda dapat menyesuaikannya dengan kebutuhan Anda dalam bahasa yang Anda gunakan. Masalah dalam kasus saya bukan tentang baris baru seperti yang saya pikirkan, tetapi tentang / tidak melarikan diri. Saya harap ini mencegah orang lain dari sakit kepala kecil saya telah mencari tahu apa yang saya lakukan salah.


2
6 singkatan untuk karakter kontrol yang ditentukan pada json.org bukanlah daftar lengkap dari semua karakter kontrol. Akibatnya, fungsi ini dapat menghasilkan JSON yang tidak valid.
Phil

-5

Seperti yang saya mengerti Anda pertanyaan, itu bukan tentang parsing JSON karena Anda dapat copy-paste JSON Anda ke dalam kode Anda langsung - jadi jika hal ini terjadi maka hanya menyalin JSON Anda langsung ke dataObjvariabel tanpa membungkusnya dengan tanda kutip tunggal (tip: eval==evil)

var dataObj = {"count" : 1, "stack" : "sometext\n\n"};

console.log(dataObj);

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.