Як обробляти нові рядки в JSON?


289

Я створив деякий JSON і намагаюся втягнути його в об’єкт у JavaScript. Я продовжую отримувати помилки. Ось що я маю:

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

Це дає мені помилку:

unterminated string literal

З JSON.parse(data), я бачу подібні повідомлення про помилки: " Unexpected token ↵" в Chrome і " unterminated string literal" в Firefox та IE.

Коли я виймаю \nпісля, sometextпомилка усувається в обох випадках. Я, здається, не можу зрозуміти, чому це \nробить evalі JSON.parseне вдається.


19
Спробуйте використовувати справжній json парсер замість eval.
Ерік

Відповіді:


368

Я думаю, це те, що ти хочеш:

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

(Вам потрібно уникнути "\" у рядку (перетворивши його у подвійне - "\"), інакше він стане новим рядком у джерелі JSON, а не даними JSON.)


101
Це, звичайно, правильно, але я хотів би додати причину для цього: специфікація JSON на ietf.org/rfc/rfc4627.txt містить це речення в розділі 2.5: "Усі символи Unicode можуть бути розміщені в лапки, за винятком символів, які слід уникнути: лапки, зворотного солідуса та контрольних символів (U + 0000 до U + 001F). " Оскільки новий рядок є контрольним символом, його потрібно уникати.
daniel kullmann

1
За даними www.json.org, JSON приймає послідовність керування "\ n" у рядках - і якщо ви спробуєте JSON.parse (['"a \\ na"']) [1] .charCodeAt (); це покаже 10 - що було "Linefeed" востаннє, коли я перевіряв. --- BTW: Перестань кричати!
BlaM

+ 1. У мене виникли проблеми з розумінням кодування JSON, але "стане новим рядком у джерелі JSON, а не даними JSON", для мене це стало зрозумілим.
amucunguzi

44

Вам знадобиться функція, яка замінює \nна \\nвипадок, якщо dataце не є літеральним рядком.

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));

Результатом dataObjбуде

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

3
вам потрібно уникнути своїх символів втечі (тобто .replace("\\n", "\\\\n")), і я б також запропонував використовувати regex, щоб дозволити замінити кілька екземплярів (тобто .replace(/\n/g, "\\\\n"))
musefan

2
навіщо вам бігти втечі персонажів? Я маю на увазі щось на кшталт .replace("\n", "\\n")повинно зробити роботу прекрасно !! Наприклад, var test = [{"description":"Some description about the product. This can be multi-line text."}]; console.log(JSON.parse(test.replace(/\n/g, "\\n")));виведе об’єкт ідеально добре на консоль браузера як[{"description":"Some description about the product.\nThis can be multi-line text."}]
Fr0zenFyr

BTW, у коментарі вище, оригінальний рядок JSON має новий рядок, який видаляється форматком коментарів stackoverflow. Ви можете бачити, що підсумковий результат після заміни повинен вставляти новий рядок \nу значення.
Fr0zenFyr

1
-1 Ця відповідь спочатку будує рядок недійсного JSON (оскільки новий рядок є символом керування), потім намагається виправити його за допомогою ряду неповних замін (є більше 3 символів управління). Потім, щоб доповнити це, він також вдається використовувати evalфункцію. 17 заявок ???
Філ

1
А як щодо лапок, які також потрібно уникати?
самостійно

8

Відповідно до специфікації, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf :

Рядок - це послідовність точок коду Unicode, обгорнутих лапками ( U+0022). Усі символи можуть бути розміщені в лапках, за винятком символів, які слід уникати: лапки ( U+0022), зворотного солідуса ( U+005C) та контрольних символів U+0000до U+001F. Існують двозначні подання послідовності втечі деяких символів.

Таким чином, ви не можете передати 0x0Aабо 0x0Cкодувати безпосередньо. Це заборонено! Специфікація пропонує використовувати послідовності евакуації для деяких чітко визначених кодів від U+0000до U+001F:

  • \fпредставляє символ подачі форми ( U+000C).
  • \nпредставляє символ подачі рядка ( U+000A).

Оскільки більшість мов програмування використовується \для цитування, вам слід уникати синтаксису евакуації (подвійний втеча - один раз для мови / платформи, один раз для самого JSON):

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

3

Ви можете просто уникнути рядка на сервері, записуючи значення поля JSON, і скасувати його, наприклад, під час отримання значення в клієнтському браузері.

Реалізація JavaScript у всіх основних браузерах має команду unescape.

Приклад:

На сервері:

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

У браузері:

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

2

Ви можете вивчити цю функцію C #, щоб уникнути рядка:

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
Чому це втече >?
нічогонеобхідного

0

Я використовував цю функцію, щоб викреслити дані з нового рядка чи інших символів для аналізу даних 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
У більшості мов у вас є кращі способи зняти наголоси з рядків unicode, ніж записати власну функцію відображення. Дивіться це питання для прикладу в Пітоні: stackoverflow.com/questions/517923 / ...
MiniQuark

у вас є багато способів керування спеціальними символами різними мовами.
ShivarajRH

2
Це взагалі погано, щоб зняти їх взагалі. Краще кодувати їх як числові символи XML, а потім розшифрувати при отриманні кінця.
Annarfych

0

JSON.stringify

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

перетворить вищезазначений рядок у

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

як згадується тут

json stringify

Ця функція додає подвійні лапки на початку та в кінці вхідного рядка та уникає спеціальних символів JSON. Зокрема, новий рядок замінюється символом \ n, вкладка замінюється символом \ t, зворотна косою рисою замінюється двома косою косою рисою \, а перед кожним лапкою розміщується зворотна риса.


4
Це лише кодова відповідь на питання одинадцяти років із вісьмома іншими відповідями. Корисно пояснити код, а також пояснити, який новий аспект питання стосується вашої відповіді, і якщо проходження часу та випуск нових версій впливають на вашу відповідь.
Джейсон Аллер

-1

Я зіткнувся з цією проблемою під час створення класу в PHP 4, щоб імітувати json_encode (доступний у PHP 5). Ось що я придумав:

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.'"';
    }
}

Я дотримувався згаданих тут правил . Я використовував лише те, що мені було потрібно, але вважаю, що ви можете адаптувати його до ваших потреб мовою, якою ви користуєтесь. Проблема в моєму випадку полягала не в нових рядках, як я спочатку думала, а в тому, що / не уникнути. Я сподіваюся, що це заважає комусь іншому від маленького головного болю, я зрозумів, що я зробив не так.


2
Шість скорочень контрольних символів, вказаних на json.org, не є вичерпним списком усіх контрольних символів. В результаті ця функція може генерувати недійсний JSON.
Філ

-5

Як я вас розумію питання, мова йде не про розборі JSON , тому що ви можете скопіювати і вставити свій JSON в код безпосередньо - так що якщо це так , то просто скопіювати ваш JSON безпосередньо до dataObjзмінної без упаковки його в одинарні лапки (підказка: eval==evil)

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

console.log(dataObj);

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.