【问题标题】:Removing ": " from JSON-like data从类似 JSON 的数据中删除“:”
【发布时间】:2016-08-11 07:51:24
【问题描述】:

我有一个 1,00,000 行的 JSON 文本文件。手动提取是不公平的。我写了一个 Perl 程序来读取文件的每一行,满足我的需要。

这是一个示例文本文件

示例.txt

  "key": "Programming",
  "doc_count": 1
  
  "key": "Base",
  "doc_count": 1,
  
  "key": "Experience",
  "doc_count": 1

  "key": "Electrophoresis",
  "doc_count": 1

我想单独使用双括号分隔的键值,例如 Programming、Base、Experience 和 Electrophoresis

这是我尝试过的 Perl 代码:

ExtractKeyValue.pl

use strict;
use warnings;

my $file = $ARGV[0];
open my $info, $file or die "Could not open $file: $!";

while ( my $line = <$info> ) {
    if ( $line =~ /"key(.*)",/ ) {
        print $1;
        print "\n";
    }
}

close $info;

通过使用这个,我得到了这个输出

": "Programming
": "Base
": "Experience
": "Electrophoresis

我不想要前导冒号和空格。

我试过$line =~ /"key: "(.*)",/。但它不起作用。命令执行,但没有输出,也没有错误症状。

G:\ExtractKeyValue_Regex>perl ExtractKeyValue.pl Sample.txt > Output_Sample.txt

G:\ExtractKeyValue_Regex>

输出应该是这样的,

预期输出:

Programming
Base
Experience
Electrophoresis

我不明白为什么该模式不跟踪冒号 : 以及空格和双引号 "

【问题讨论】:

  • 您缺少报价:"key": ,而不是 "key:
  • 请注意语言被称为Perl

标签: regex perl


【解决方案1】:

用你所需要的线条来展示

my $key_assoc = $line =~ /: "([^"]+)/;

print "$key_assoc\n" if $key_assoc;

或者您可以输入"key" 字符串和", 以获得额外的保证和格式检查

if ($line =~ /"key": "([^"]+)",/) {
    # ...
}

请注意,如果有空引号 ("key": "",),+ 会使其捕获任何内容,而 .* 在这种情况下会为您提供空字符串。一个可能无关紧要的细节,但它们是不同的。


请注意,在正则表达式中使用单个文字空格   很容易被忽略(或加倍),并且如果稍后添加 /x 也会被吞没,如果未经测试会引入错误.

指定单个简单空间的更好方法?我们可以通过charnames pragma 使用\x20 或Unicode \N{SPACE}。感谢 Borodin 提出并指定这两个。

来自Sinan Ünür 的一个很好的解决方法是使用只有空格的字符类/a [ ] b/x。这既强调文字空间是有意的(没有/x),又允许在/x下使用。

另一个解决方法是显式转义它,/\ /,这会引起对它的注意并保护它免受/x 的影响。

【讨论】:

  • @MJSuriya 太好了 :) 感谢您的反馈和归属。我在最后添加了",,因为我认为将它作为额外的格式检查很好(就像你拥有它一样)。
  • @zdim:我不喜欢正则表达式模式中的文字空格,因为它们很容易被误读,如果有/x 有效修饰符,它们就会完全打折。对于正常情况,您有 \s\h,但是要用图形字符精确表达一个空格,我知道的莫过于 \x20\N{SPACE}
  • @Borodin 感谢您的评论——多年来,这一直困扰着我,如何(良好而安全地)指定一个简单的空间。我一直认为在某个地方隐藏着一些简单而干净的东西。在您提供的两者之间也很难做出决定(谢谢),但我倾向于使用 Unicode charnames ...?我会研究的。我想另一个解决方案(我曾经使用过)是明确地逃避它,以引起注意并防止/x,但这肯定不漂亮。我在帖子中添加了一个注释,谢谢。
  • @SinanÜnür 对,谢谢——这比逃避它要好得多。已添加。
【解决方案2】:

你应该使用这个:

"key": "(.*?)"

在正则表达式检查中进行:

if($line =~ /"key": "(.*?)",/){
   ...

这样,第一个捕获组 ($1) 将包含您想要的内容。

【讨论】:

    【解决方案3】:

    这就是我要写的。它扫描输入文件中的每一行以查找两个双引号字符串,然后打印第二个(如果存在)

    use strict;
    use warnings 'all';
    
    my ($file) = @ARGV;
    
    open my $fh, $file or die qq{Could not open "$file": $!};
    
    while ( <$fh> ) {
    
        my ($key, $val) = / " ( [^"]+ ) " /xg;
    
        next unless $key and $key eq 'key';
    
        print $val, "\n" if $val;
    }
    

    输出

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-23
      • 1970-01-01
      • 2017-12-14
      • 2020-07-21
      • 2019-05-01
      • 2020-04-01
      • 1970-01-01
      • 2015-03-13
      相关资源
      最近更新 更多