我正在尝试将JSON格式的数据(https://rest.kegg.jp/get/br:ko00001/json)转换为CSV/TSV。我已经能够在awk和sed中完成此操作,但我正在学习Perl以用于更大的项目,因此学习在没有JSON模块的情况下完成此操作会很有帮助。
sed -E 's/^\t{2}"name"/\t\t"level 1"/g;s/^\t{3}"name"/\t\t\t"level 2"/g;s/^\t{4}"name"/\t\t\t\t"level 3"/g;s/^\t{5}"name"/\t\t\t\t\t"level 4"/g' json.json | awk 'BEGIN {OFS="\t"} NR > 4 {match($0, /"([^"]+)": *("[^"]*")/, a)} {tag = a[1]; val = gensub(/^"|"$/, "", "g", a[2]); f[tag] = val; if (tag == "level 4") {print f["level 1"], f["level 2"], f["level 3"], f["level 4"]}}' > table.tsv
上面是我如何通过awk和sed制作的。json.json是从链接下载的。
下面是我到目前为止在没有JSON模块的情况下在Perl中所做的尝试。我想通过这种方式来了解数据结构和Perl的工作原理。
use strict;
my $brite_hierarchy_filepath = shift @ARGV;
open my $brite_hierarchy, '<:utf8', $brite_hierarchy_filepath or die q{Can't open $brite_hierarchy_filepath: $!\n};
while (my $line = <$brite_hierarchy>) {
next if $. == 4;
chomp $line;
$line =~ s/\A\t{2}"name"/"level_1"/;
$line =~ s/\A\t{3}"name"/"level_2"/;
$line =~ s/\A\t{4}"name"/"level_3"/;
$line =~ s/\A\t{5}"name"/"level_4"/;
my ($tag) = $line =~ /\A"(.*?)"/;
my ($value) = $line =~ /\A"level_[1-4]":"(.*?)"/;
my %field = ($tag => $value) unless $tag eq "" && $value eq "";
for (keys %field) {
print join("\t", $field{"level_1"}, $field{"level_2"}, $field{"level_3"}, $field{"level_4"}, "\n");
};
last if eof $brite_hierarchy;
};
这是数据的简要外观。
{
"name":"ko00001",
"children":[
{
"name":"09100 Metabolism",
"children":[
{
"name":"09101 Carbohydrate metabolism",
"children":[
{
"name":"00010 Glycolysis \/ Gluconeogenesis [PATH:ko00010]",
"children":[
{
"name":"K00844 HK; hexokinase [EC:2.7.1.1]"
},
{
"name":"K12407 GCK; glucokinase [EC:2.7.1.2]"
},
{
"name":"K00845 glk; glucokinase [EC:2.7.1.2]"
...
和TSV格式的所需输出。
09100 Metabolism 09101 Carbohydrate metabolism 00010 Glycolysis \/ Gluconeogenesis [PATH:ko00010] K00844 HK; hexokinase [EC:2.7.1.1]
09100 Metabolism 09101 Carbohydrate metabolism 00010 Glycolysis \/ Gluconeogenesis [PATH:ko00010] K12407 GCK; glucokinase [EC:2.7.1.2]
09100 Metabolism 09101 Carbohydrate metabolism 00010 Glycolysis \/ Gluconeogenesis [PATH:ko00010] K00845 glk; glucokinase [EC:2.7.1.2]
3条答案
按热度按时间hlswsv351#
我总是建议使用JSON解析器,但如果您能保证格式永远不变,您确实可以将其视为固定的文本文件。在生产环境中,您通常无法做到这一点。但如果它是一次性的,那么它当然可以工作。
您粘贴到问题中的示例输入包含空格,而不是制表符,因此您的代码无法在其上工作。我的代码也无法在其上工作。我的输入是从您的链接复制的,并且包含制表符。
你的正则表达式模式看起来有点复杂。你可以总是有相同的简单模式,但是只需要改变每个名字前面的制表符的数量。诀窍是当你发现一个名字不是最后一列时跳到下一行,并在第一列重置整个结构。我选择使用数组而不是哈希。因为这样更有意义,我们可以在以后输出的时候使用
join
。最后,say
类似于print
,但是有一个内置的换行符。bttbmeg02#
不使用JSON解析器是可怕的。
xn1cxnb43#
尽管代码看起来不是很清晰,但我还是设法创建了TSV格式的表,与sed和awk生成的表非常相似。
感谢所有关于使用模块JSON的信息,但是通过这种方式,我了解了更多关于在循环块外部使用变量的信息,我们可以存储它以用于循环中的下一轮。