簡體   English   中英

所有 JSON 字符串在語法上是否也有效 Python 字符串文字?

[英]Are all JSON strings also syntactically valid Python string literals?

我正在寫一個 JavaScript function 生成一個 Python 程序。 我可以在字符串上使用 JavaScript 的JSON.stringify()並每次都期望有效的 Python 字符串嗎?或者是否存在意味着我必須編寫自己的toPythonString() function 的邊緣情況?

最簡潔的答案是不。

長答案在實踐中是肯定的。 幾乎。 不同之處在於 JSON 字符串可以有正斜杠反斜杠轉義。 因此字符串"\/"被 JSON (和 JavaScript)解釋為單個正斜杠'/'但作為反斜杠后跟正斜杠 Python '\\/'

但是,在 JSON 中以這種方式序列化正斜杠不是強制性的。 如果您可以控制 JSON 序列化程序並且可以確保它不會反斜杠轉義正斜杠,那么您的 JSON 字符串應該始終是有效的 ZA7F5F35426B927411FC9231B5638 字符串。

查看V8中 JSON 序列化程序的源代碼(Google Chrome 和 Node.js 的 JavaScript 引擎),它總是將'/'序列化為"/" ,正如您所期望的那樣。


JSON 字符串語法記錄在json.org和 Python 字符串語法記錄在其文檔的詞匯分析部分。

We can see that a regular JSON string character is "Any codepoint except " , \ or control characters" whereas Python string characters are "Any source character except \ or newline or the quote". Since newline is a control character, this means JSON is比 Python 更嚴格,這很好。那么問題是“任何代碼點”和“任何源字符”之間的重疊是什么?我不知道如何回答,但我猜它們可能是相同的, assuming both the JSON and Python are encoded in UTF-8. (If you're interested in JavaScript strings instead of JSON strings, then JavaScript is generally encoded in UTF-16, so there could be some incompatibilities arising from that here.)

我們還看到 JSON 有一些反斜杠轉義,除了一個轉義的正斜杠\/之外,Python 都支持這些轉義。 這是 Python 不共享的 JSON 字符串的一部分。

最后,在 JSON 中,我們可以使用\uXXXX語法來轉義任何字符,Python 也支持這一點。

如果你想在 JavaScript 中序列化一個字符串為 Python 的源碼,可以這樣做:

const regexSingleEscape = /'|\\|\p{C}|\p{Z}/gu;
const regexDoubleEscape = /"|\\|\p{C}|\p{Z}/gu;

function asPythonStr(s) {
  let quote = "'";
  if (s.includes("'") && !s.includes('"')) {
    quote = '"';
  }
  const regex = quote === "'" ? regexSingleEscape : regexDoubleEscape;
  return (
    quote +
    s.replace(regex, (c: string): string => {
      switch (c) {
        case " ":
          return " ";
        case "\x07":
          return "\\a";
        case "\b":
          return "\\b";
        case "\f":
          return "\\f";
        case "\n":
          return "\\n";
        case "\r":
          return "\\r";
        case "\t":
          return "\\t";
        case "\v":
          return "\\v";
        case "\\":
          return "\\\\";
        case "'":
        case '"':
          return "\\" + c;
      }
      const hex = (c.codePointAt(0) as number).toString(16);
      if (hex.length <= 2) {
        return "\\x" + hex.padStart(2, "0");
      }
      if (hex.length <= 4) {
        return "\\u" + hex.padStart(4, "0");
      }
      return "\\U" + hex.padStart(8, "0");
    }) +
    quote
  );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM