json - 如何在 AWK 中打印 JSON 对象

标签 json awk text-mining

我一直在寻找 awk 中的一些内置函数来轻松生成 JSON 对象。我找到了几个答案,并决定创建自己的答案。

我想从多维数组(我在其中存储表格样式数据)生成 JSON,并使用从该数据生成的 JSON 架构的单独动态定义。

期望的输出:

{
"Name": JanA
"Surname": NowakA
"ID": 1234A
"Role": PrezesA
}
{
"Name": JanD
"Surname": NowakD
"ID": 12341D
"Role": PrezesD
}
{
"Name": JanC
"Surname": NowakC
"ID": 12342C
"Role": PrezesC
}

输入文件:

pierwsza linia
druga linia
trzecia linia

dane wspólników
imie JanA
nazwisko NowakA
pesel 11111111111A
funkcja PrezesA

imie Ja"nD
nazwisko NowakD
pesel 11111111111
funkcja PrezesD

imie JanC
nazwisko NowakC
pesel 12342C
funkcja PrezesC

czwarta linia

reprezentanci

imie Tomek

根据输入文件我创建了一个多维数组:

JanA  NowaA 1234A PrezesA
JanD  NowakD 12341D PrezesD
JanC  NowakC 12342C PrezesC

最佳答案

我会尝试一个 gawk 解决方案。缩进并不完美,结果也没有排序(请参阅下面的“排序”注释),但它至少能够递归地遍历真正的多维数组,并且应该从任何数组生成有效的、可解析的 JSON。 奖励:数据数组就是架构。数组键变成 JSON 键。除了数据数组之外,无需创建单独的架构数组。

请务必使用true multidimensional array[d1][d2][d3]... 构造数据数组的约定,而不是 concatenated index 数组[d1,d2,d3...]约定。

更新:

我有一个更新的 JSON gawk 脚本,发布为 GitHub Gist 。尽管下面的脚本经过了使用 OP 数据的测试,自上次编辑这篇文章以来,我可能已经做出了改进。请参阅要点,了解经过最彻底测试、消除错误的版本。

#!/usr/bin/gawk -f

BEGIN { IGNORECASE = 1 }

$1 ~ "imie" { record[++idx]["name"] = $2 }
$1 ~ "nazwisko" { record[idx]["surname"] = $2 }
$1 ~ "pesel" { record[idx]["ID"] = $2 }
$1 ~ "funkcja" { record[idx]["role"] = $2 }

END { print serialize(record, "\t") }

# ==== FUNCTIONS ====

function join(arr, sep, _p, i) {
    # syntax: join(array, string separator)
    # returns a string

    for (i in arr) {
        _p["result"] = _p["result"] ~ "[[:print:]]" ? _p["result"] sep arr[i] : arr[i]
    }
    return _p["result"]
}

function quote(str) {
    gsub(/\\/, "\\\\", str)
    gsub(/\r/, "\\r", str)
    gsub(/\n/, "\\n", str)
    gsub(/\t/, "\\t", str)
    return "\"" str "\""
}

function serialize(arr, indent_with, depth, _p, i, idx) {
    # syntax: serialize(array of arrays, indent string)
    # returns a JSON formatted string

    # sort arrays on key, ensures [...] values remain properly ordered
    if (!PROCINFO["sorted_in"]) PROCINFO["sorted_in"] = "@ind_num_asc"

    # determine whether array is indexed or associative
    for (i in arr) {
        _p["assoc"] = or(_p["assoc"], !(++_p["idx"] in arr))
    }

    # if associative, indent
    if (_p["assoc"]) {
        for (i = ++depth; i--;) {
            _p["end"] = _p["indent"]; _p["indent"] = _p["indent"] indent_with
        }
    }

    for (i in arr) {
        # If key length is 0, assume its an empty object
        if (!length(i)) return "{}"

        # quote key if not already quoted
        _p["key"] = i !~ /^".*"$/ ? quote(i) : i

        if (isarray(arr[i])) {
            if (_p["assoc"]) {
                _p["json"][++idx] = _p["indent"] _p["key"] ": " \
                    serialize(arr[i], indent_with, depth)
            } else {
                # if indexed array, dont print keys
                _p["json"][++idx] = serialize(arr[i], indent_with, depth)
            }
        } else {
            # quote if not numeric, boolean, null, already quoted, or too big for match()
            if (!((arr[i] ~ /^[0-9]+([\.e][0-9]+)?$/ && arr[i] !~ /^0[0-9]/) ||
                arr[i] ~ /^true|false|null|".*"$/) || length(arr[i]) > 1000)
                arr[i] = quote(arr[i])

            _p["json"][++idx] = _p["assoc"] ? _p["indent"] _p["key"] ": " arr[i] : arr[i]
        }
    }

    # I trial and errored the hell out of this. Problem is, gawk cant distinguish between
    # a value of null and no value.  I think this hack is as close as I can get, although
    # [""] will become [].
    if (!_p["assoc"] && join(_p["json"]) == "\"\"") return "[]"

    # surround with curly braces if object, square brackets if array
    return _p["assoc"] ? "{\n" join(_p["json"], ",\n") "\n" _p["end"] "}" \
        : "[" join(_p["json"], ", ") "]"
}

OP 示例数据的输出:

[{
        "ID": "1234A",
        "name": "JanA",
        "role": "PrezesA",
        "surname": "NowakA"
}, {
        "ID": "12341D",
        "name": "JanD",
        "role": "PrezesD",
        "surname": "NowakD"
}, {
        "ID": "12342C",
        "name": "JanC",
        "role": "PrezesC",
        "surname": "NowakC"
}, {
        "name": "Tomek"
}]

排序

虽然默认情况下结果以只有 gawk 理解的方式排序,但 gawk 可以对字段上的结果进行排序。例如,如果您想对 ID 字段进行排序,请添加此函数:

function cmp_ID(i1, v1, i2, v2) {
    if (!isarray(v1) && v1 ~ /"ID"/ ) {
        return v1 < v2 ? -1 : (v1 != v2)
    }
}

然后将此行插入到 print serialize(record) 上方的 END 部分中:

PROCINFO["sorted_in"] = "cmp_ID"

参见Controlling Array Traversal了解更多信息。

关于json - 如何在 AWK 中打印 JSON 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50477885/

相关文章:

windows - 如何获取非常不寻常的格式文本文件的必要值?

shell - 如何设置终端的选项卡大小(不带 "tabs"或 "expand")

R tm 包和西里尔文字

java - NLP for java,我应该使用哪个工具包?

ruby-on-rails - Rails 和 docker - 无法安装 json gem

json - WCF 服务速度慢 - 有选项吗?

javascript - 如何从 Kaizala API 获取 accessToken

regex - sed 或 awk 正则表达式,在分号后停止匹配

java - 多标签文档分类

java - 如何使用 ObjectMapper 加载 JSON 以映射到特定的类结构?