【问题标题】:Is there a simple way to customize how arrays are formatted by JSON.stringify?有没有一种简单的方法来自定义 JSON.stringify 如何格式化数组?
【发布时间】:2019-05-19 10:58:03
【问题描述】:

我经常想要“漂亮地打印”(包括额外的空白以使人类更容易解释)JavaScript 对象,而JSON.stringify(myObject, null, " ") 通常就足够了。但是,在许多情况下,有些数字数组我真的不想拆分到新行上。

是否有一种简单/优雅的方法可以使用native JSON.stringify function 完成此任务?

我尝试使用“替换器”功能,但这似乎只有助于更改(例如修改数据)、过滤(例如省略数据)和副作用(例如日志数据)——另请参阅 How Do I Use The Replacer Function With JSON Stringify?。

或者,是否有已建立的模块/库/实用程序可以执行此操作,还是我应该自己编写?

似乎有many search results on npm.org for "stringify",但我看到的似乎只是变体,它们要么在特定问题域上更有效地运行,要么避免与循环/循环数据结构相关的问题。

const obj = {
  foo: "bar",
  oneLine: [1,2,3],
  multipleLines: [{
    name: "X",
    alsoOneLine: [4,5,6]
  }, {
    name: "Y"
  }]
};

document.write(`
  <pre>
    // This isn't the output I want. 
    // The arrays containing only numbers should have their elements
    // all printed on the same line.
    ${JSON.stringify(obj, null, "  ")}
  </pre>
`);

【问题讨论】:

    标签: javascript json serialization stringify


    【解决方案1】:

    您可以使用正则表达式在字符串化版本中搜索数字数组,并将所有这些数字数组中的空格替换为空字符串。通过使用^ 将模式的开头锚定到行的开头,您可以确保匹配的键值对(或普通值,如果数字数组包含在另一个数组中)是 array,而不是其他东西,比如一个包含看起来像 JSON-array-of-numbers 的东西的字符串:

    const obj = {
      foo: "bar",
      oneLine: [1, 2, 3],
      multipleLines: [{
        name: "X",
        alsoOneLine: [4, 5, 6],
        inner: [
          [1, 2, 3],
          [4, 5, 6]
        ]
      }, {
        name: "Y"
      }]
    };
    
    const stringified = JSON.stringify(obj, null, "  ");
    const numArraysOnOneLine = stringified.replace(
      /^( *)("[^"]+": )?(\[(?:\s+\d+,)*\s+\d+\s+\])/gm,
      (_, leadingWhitespace, possibleKeyStr='', arrStr) => (
        leadingWhitespace + possibleKeyStr + arrStr.replace(/\s+/g, ''
      ))
    );
    document.write(`<pre>${numArraysOnOneLine}</pre>`);

    https://regex101.com/r/XfuqoT/1

    模式

    ^( *)("[^"]+": )?(\[(?:\s+\d+,)*\s+\d+\s+\])
    

    意思是:

    • ^ - 匹配行首
    • ( *)第一个捕获组:捕获前导空格
    • ("[^"]+": )? 第二组,可选:如果数组包含在对象中,则匹配双引号键
    • \[ - 第三组开始。匹配文字 [
    • (?:\s+\d+,)* - 重复一组空白字符,后跟数字零次或多次
    • \s+\d+\s+ - 匹配数组中的最后一项(没有尾随逗号):空格,后跟一个数字,然后是更多空格
    • \] - 后跟终止 ](第三组结束)

    如果数字也可能包含小数,则将 \d+ 替换为 \d+(?:\.\d+)? 以允许可选的小数位。

    如果对象属性也可能包含双引号(字符串化时用反斜杠转义),则将 [^"]+ 替换为 (?:[^"]|\\")+ https://regex101.com/r/XfuqoT/2

    【讨论】:

    • 它可能会破坏数据:str: "[ 4, 5, 6 ]",
    • 对JSON.stringify 的结果进行后处理是一个有趣的想法。尽管可能存在许多“陷阱”,但我对指望 RegEx 的正确性有点怀疑。我更喜欢更易于验证的程序化方法。
    • 也许这可以与一个“替换器”函数结合使用,该函数标识要由后处理 RegEx 处理的属性,例如如果找到包含所有数字的数组,则可以将其修改为具有所需结果的字符串,但前缀为特殊序列,例如 __CONVERT_THIS_STRING_TO_AN_ARRAY__,RegEx 可以检测并删除该序列以及引号,使其再次成为数组。跨度>
    • @iX3 我最初确实想过这样的事情,但它看起来像是一个丑陋的黑客。但是toJSON 方法似乎已经产生了您正在寻找的输出(正确,没有边缘情况,假设 ES6),对吧?
    • 糟糕,抱歉,不,它不起作用。您提供的 toJSON 解决方案会导致数组成为带引号的字符串。 toJSON behavior: "...不是对对象进行序列化,而是对 toJSON() 方法调用时返回的值进行序列化。"
    猜你喜欢
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多