【问题标题】:Break down JSON string in simple perl or simple unix?在简单的 perl 或简单的 unix 中分解 JSON 字符串?
【发布时间】:2012-02-20 02:56:26
【问题描述】:

好的,我有这个

{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}

目前我正在使用这个 shell 命令对其进行解码以获得我需要的字符串,

echo $x | grep -Po '"utterance":.*?[^\\]"' | sed -e s/://g -e s/utterance//g -e 's/"//g'

但这仅适用于您使用 perl 编译的 grep 以及我用来获取 JSON 字符串的脚本是用 perl 编写的,所以有什么方法可以在简单的 perl 脚本或更简单的脚本中进行相同的解码unix 命令,还是更好的 c 或 Objective-c?

我用来获取 json 的脚本在这里,http://pastebin.com/jBGzJbMk,如果你想使用文件,请下载http://trevorrudolph.com/a.flac

【问题讨论】:

  • 你需要的字符串是什么?发布你想要的输出,而不是你用来获取输出的命令。
  • 哦!抱歉,我只是从那开始,“你好,你好吗”

标签: objective-c c json perl unix


【解决方案1】:

怎么样:

perl -MJSON -nE 'say decode_json($_)->{hypotheses}[0]{utterance}'

脚本形式:

use JSON;
while (<>) {
   print decode_json($_)->{hypotheses}[0]{utterance}, "\n"
}

【讨论】:

  • echo {"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]} | perl -MJSON -pe 'decode_json($_)-&gt;{hypotheses}[0]{utterance}'
  • malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "status:0 id:7aceb216...") at -e line 1, &lt;&gt; line 1.
  • id 喜欢它的常规脚本形式,我正在运行一个 .pl 脚本来获取该字符串以进行打印,因此在打印之前解码可能会很好
  • @Trevor Rudolph,你没有正确引用你的 JSON。
  • 我会添加 -000 来处理多行 JSON。此外,输出数组的第一个元素肯定看起来很可疑。
【解决方案2】:

好吧,我不确定我是否能正确推断出你所追求的,但这是一种在 perl 中解码 JSON 字符串的方法。

当然,您需要了解数据结构才能获得所需的数据。打印“话语”字符串的行在下面的代码中被注释掉了。

use strict;
use warnings;
use Data::Dumper;
use JSON;

my $json = decode_json 
q#{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}#;
#print $json->{'hypotheses'}[0]{'utterance'};
print Dumper $json;

输出:

$VAR1 = {
          'status' => 0,
          'hypotheses' => [
                            {
                              'utterance' => 'hello how are you',
                              'confidence' => '0.96311796'
                            }
                          ],
          'id' => '7aceb216d02ecdca7ceffadcadea8950-1'
        };

快速破解:

while (<>) {
    say for /"utterance":"?(.*?)(?<!\\)"/;
}

或者作为单行:

perl -lnwe 'print for /"utterance":"(.+?)(?<!\\)"/g' inputfile.txt

如果你碰巧使用的是 Windows,那么单行就很麻烦,因为 " 是由 shell 解释的。

快速破解#2:

这有望通过任何哈希结构并找到键。

my $json = decode_json $str;
say find_key($json, 'utterance');

sub find_key {
    my ($ref, $find) = @_;
    if (ref $ref) {
        if (ref $ref eq 'HASH' and defined $ref->{$find}) {
            return $ref->{$find};
        } else {
            for (values $ref) {
                my $found = find_key($_, $find);
                if (defined $found) {
                    return $found;
                }
            }
        }
    }
    return;
}

【讨论】:

  • 但我希望它足够简单,所以我不需要从 CPAN 获取 JSON 并且话语是变量吗?还是参考?
  • @TrevorRudolph 在上面的$json 变量中,它是一个哈希键。不太清楚你在那里问什么。尝试用正则表达式解析它的问题是转义引号。 "hello my name is \"Bob\"." 之类的字符串需要您跳过一些环节才能正确解析。
  • 是的,但我能用你得到的东西做些什么吗,print Dumper $json-&gt;'utterance';
  • @TrevorRudolph 您的意思是在结构中打印名称为“utterance”的任何键?我想这是可能的。
  • 是的,打印json键'utterance'的字符串
【解决方案3】:

根据命名,可能有多个假设。打印每个假设的话语:

echo '{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}' | \
   perl -MJSON::XS -n000E'
      say $_->{utterance}
         for @{ JSON::XS->new->decode($_)->{hypotheses} }'

或者作为脚本:

use feature qw( say );
use JSON::XS;
my $json = '{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}';
say $_->{utterance}
   for @{ JSON::XS->new->decode($json)->{hypotheses} };

【讨论】:

  • malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "status:0 id:7aceb216...") at -e line 2, &lt;&gt; chunk 1.
  • 根据要求更改为看起来像一个脚本。
  • @Trevor Rudolph,那是什么?你是说你有无效的JSON?它适用于您在 OP 中提供的 JOSN。
  • @Trevor Rudolph,哦,我明白了,你删除了我代码中的引号。不要那样做。
  • 不,我仍然收到格式错误的 json 字符串引号
【解决方案4】:

如果您不想使用 CPAN 中的任何模块并尝试使用正则表达式,您可以尝试多种变体:

# JSON is on a single line:
$json = '{"other":"stuff","hypo":[{"utterance":"hi, this is \"bob\"","moo":0}]}';
# RegEx with negative look behind:
# Match everything up to a double quote without a Backslash in front of it
print "$1\n" if ($json =~ m/"utterance":"(.*?)(?<!\\)"/)

如果只有一个话语,则此正则表达式有效。它周围的字符串中还有什么并不重要,因为它只搜索话语键后面的双引号字符串。

对于更强大的版本,您可以在必要/可能的地方添加空格,并使 RegEx 中的 . 匹配换行符:m/"utterance"\s*:\s*"(.*?)(?&lt;!\\)"/s

如果您有多个话语置信度哈希/对象条目、JSON 字符串的大小写变化和奇怪的格式,请尝试以下操作:

# weird JSON:
$json = <<'EOJSON';
{
    "status":0,
    "id":"an ID",
    "hypotheses":[
        {
            "UtTeraNcE":"hello my name is \"Bob\".",
            "confidence":0.0
        },
        {
            'utterance' : 'how are you?',
            "confidence":0.1
        },
        {
            "utterance"
                : "
                thought
                so!
                ",
            "confidence" : 0.9
        }
    ]
}
EOJSON
# RegEx with alternatives:
print "$1\n" while ( $json =~ m/["']utterance["']\s*:\s*["'](([^\\"']|\\.)*)["']/gis);

这个正则表达式的主要部分是"(([^\\"]|\\.)*)"。详细描述为扩展正则表达式:

/
["']    # opening quotes
(       # start capturing parentheses for $1
(       # start of grouping alternatives
[^\\"'] # anything that's not a backslash or a quote
|       # or
\\.     # a backslash followed by anything
)       # end of grouping
*       # in any quantity
)       # end capturing parentheses
["']    # closing quotes
/xgs

如果您有许多数据集并且速度是一个问题,您可以将 o 修饰符添加到正则表达式并使用字符类而不是 i 修饰符。您可以使用聚类括号 (?:pattern) 禁止捕获 $2 的替代项。然后你得到这个最终结果:

m/["'][uU][tT][tT][eE][rR][aA][nN][cC][eE]["']\s*:\s*["']((?:[^\\"']|\\.)*)["']/gos

是的,有时 perl 看起来像是支架工厂的一次大爆炸;-)

【讨论】:

  • 我知道你在做什么,如果我只是说$json = '{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}',它会非常有效,但我使用脚本来获取 json,让我发布脚本和测试文件的链接
  • 好的,所以当我尝试将 $response 作为变量时,过滤器不起作用
  • 当您可以将/i 修饰符添加到正则表达式时,为什么还要使用一堆[uU][tT]...
  • @Trevor 它不起作用,因为 $response 不是字符串,而是 HTTP::Response 对象。像这样修改您的测试脚本,它应该可以工作:if ( $response-&gt;is_success ) { print "$1\n" if ($response-&gt;content =~ m/["']utterance["']\s*:\s*["']((?:[^\\"']|\\.)*)["']/ios); }
  • @ChrisH 做一些基准测试,我无法检测到使用 /i 修饰符和匹配正则表达式的字符类之间的任何显着速度差异(有 2-4% 的差异有利于 /i 修饰符) .但是,对于不匹配的正则表达式,/i 修饰符要快 76%。
【解决方案5】:

刚刚偶然发现了另一种很好的方法,我终于找到了如何访问 Mac OS X JavaScript 引擎表单命令行,这是脚本,

alias jsc='/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc'
x='{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}'
jsc -e "print(${x}['hypotheses'][0]['utterance'])"

【讨论】:

    【解决方案6】:

    呃,是的,我想出了另一个答案,我正在学习 python,它读取其 python 格式和与 json 格式相同的数组,所以,当你的变量是 x 时,我只做了这个衬里

    python -c "print ${x}['hypotheses'][0]['utterance']"
    

    【讨论】:

      【解决方案7】:

      为 unix 解决了这个问题,但希望看到您的 perl 和 c、objective-c 答案...

      echo $X | sed -e 's/.*utterance//' -e 's/confidence.*//' -e s/://g -e 's/"//g' -e 's/,//g'
      

      :D

      同一 sed 的较短副本:

      echo $X | sed -e 's/.*utterance//;s/confidence.*//;s/://g;s/"//g;s/,//g'
      

      【讨论】:

      • 对于 Objective-C 有各种库,包括 Apple 在 iOS 5 中提供的库。对于 Perl,有这样的库:search.cpan.org/~makamaka/JSON-2.53/lib/JSON.pm。还是您只对避免使用库的答案感兴趣?
      • 如果它在 c 或 Objective-c 源代码中我可以,所以我可以将它全部编译到 1 个实用程序中
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 2017-04-16
      • 2023-03-08
      • 2021-12-28
      • 1970-01-01
      相关资源
      最近更新 更多