使用perl对存储在JSON中的utf8文件名进行规范化

kob*_*ame 8 perl json utf-8

我有两个来自不同操作系统的Json文件.

两个文件都编码UTF-8并包含UTF-8编码filenames.

一个文件来自OS X,文件名是NFD形式:( od -bc)

0000160   166 145 164 154 141 314 201 057 110 157 165 163 145 040 155 145
           v   e   t   l   a    ?  **   /   H   o   u   s   e       m   e
Run Code Online (Sandbox Code Playgroud)

第二个包含相同的文件名但以NFC形式:

000760   166 145 164 154 303 241 057 110 157 165 163 145 040 155 145 163
           v   e   t   l   á  **   /   H   o   u   s   e       m   e   s
Run Code Online (Sandbox Code Playgroud)

据我所知,这被称为"不同的规范化",并且有一个Unicode::Normalize用于处理它的CPAN模块.

我正在阅读下一个文件:

my $json1 = decode_json read_file($file1, {binmode => ':raw'}) or die "..." ;
my $json2 = decode_json read_file($file2, {binmode => ':raw'}) or die "..." ;
Run Code Online (Sandbox Code Playgroud)

read_file来自from File::Slurp和decode_json JSON::XS.

将JSON读入perl结构,从一个json文件中文件名key到位,从第二个文件进入values.我需要搜索的时候哈希key从第一散是等同放着清单value从第二哈希值,因此需要保证比他们"二进制"相同.

尝试下一个:

 grep 'House' file1.json | perl -CSAD -MUnicode::Normalize -nlE 'print NFD($_)' | od -bc
Run Code Online (Sandbox Code Playgroud)

 grep 'House' file2.json | perl -CSAD -MUnicode::Normalize -nlE 'print NFD($_)' | od -bc
Run Code Online (Sandbox Code Playgroud)

为我生产相同的输出.

现在的问题是:

  • 如何简单地阅读这两个JSON文件来获得相同的标准化为两个$hashrefs

还是需要decode_json在两次哈希之后运行?

while(my($k,$v) = each(%$json1)) {
    $copy->{ NFD($k) } = NFD($v);
}
Run Code Online (Sandbox Code Playgroud)

简而言之:

  • 如何读取不同的JSON文件以在perl中"内部"进行相同的规范化$href?有可能实现更好一些,因为明确地做NFD每个key value和创建另一个NFD标准化(大)的哈希副本?

一些提示,建议 - 请...

因为我的英语非常糟糕,这里是对问题的模拟

use 5.014;
use warnings;

use utf8;
use feature qw(unicode_strings);
use charnames qw(:full);
use open qw(:std :utf8);
use Encode qw(encode decode);
use Unicode::Normalize qw(NFD NFC);

use File::Slurp;
use Data::Dumper;
use JSON::XS;

#Creating two files what contains different "normalizations"
my($nfc, $nfd);;
$nfc->{ NFC('key') } = NFC('vál');
$nfd->{ NFD('vál') } = 'something';

#save as NFC - this comes from "FreeBSD"
my $jnfc =  JSON::XS->new->encode($nfc);
open my $fd, ">:utf8", "nfc.json" or die("nfc");
print $fd $jnfc;
close $fd;

#save as NFD - this comes from "OS X"
my $jnfd =  JSON::XS->new->encode($nfd);
open $fd, ">:utf8", "nfd.json" or die("nfd");
print $fd $jnfd;
close $fd;

#now read them
my $jc = decode_json read_file( "nfc.json", { binmode => ':raw' } ) or die "No file" ;
my $jd = decode_json read_file( "nfd.json", { binmode => ':raw' } ) or die "No file" ;

say $jd->{ $jc->{key} } // "NO FOUND";    #wanted to print "something"

my $jc2;
#is here a better way to DO THIS?
while(my($k,$v) = each(%$jc)) {
    $jc2->{ NFD($k) } = NFD($v);
}
say $jd->{ $jc2->{key} } // "NO FOUND";    #OK
Run Code Online (Sandbox Code Playgroud)

jm6*_*666 1

在为您的问题搜索正确的解决方案时,我发现:该软件是 c*rp :) 请参阅:https ://stackoverflow.com/a/17448888/632407 。

无论如何,找到了您的特定问题的解决方案 - 如何读取带有文件名的 json,无论标准化如何:

而不是你的:

#now read them
my $jc = decode_json read_file( "nfc.json", { binmode => ':raw' } ) or die "No file" ;
my $jd = decode_json read_file( "nfd.json", { binmode => ':raw' } ) or die "No file" ;
Run Code Online (Sandbox Code Playgroud)

使用下一个:

#now read them
my $jc = get_json_from_utf8_file('nfc.json') ;
my $jd = get_json_from_utf8_file('nfd.json') ;
...

sub get_json_from_utf8_file {
    my $file = shift;
    return
      decode_json      #let parse the json to perl
        encode 'utf8', #the decode_json want utf8 encoded binary string, encode it
          NFC          #conv. to precomposed normalization - regardless of the source
            read_file  #your file contains utf8 encoded text, so read it correctly
              $file, { binmode => ':utf8' } ;
}
Run Code Online (Sandbox Code Playgroud)

这应该(至少我希望)确保无论什么分解使用 JSON 内容,NFC都会将其转换为预组合版本,并且 JSON:XS 会将其正确读取解析为相同的内部 perl 结构。

所以你的例子打印:

something
Run Code Online (Sandbox Code Playgroud)

无需遍历$json

这个想法来自约瑟夫·迈尔斯和尼莫;)

也许一些更熟练的程序员会给出更多提示。