Perl和Ruby之间的YAML数据交换问题
我在Perl和Ruby之间通过YAML交换数据时遇到了问题。我有一些看起来像number:number的值,比如Perl和Ruby之间的YAML数据交换问题,ruby,perl,yaml,Ruby,Perl,Yaml,我在Perl和Ruby之间通过YAML交换数据时遇到了问题。我有一些看起来像number:number的值,比如1:16 Perl的YAML库(Tiny和XS)将其编码为1:16,不带引号。Ruby的YAML库(Psych)没有将其解释为字符串,而是以某种方式变成了Fixnum值4560。我不知道如何解决这两方面的转换问题 对于我的用例,YAML中的每个值都应该是一个对象或字符串。因此,如果存在这样的选项,我可以告诉Perl YAML库引用所有值。或者有没有办法告诉Ruby YAML库将所有值解
1:16
Perl的YAML库(Tiny和XS)将其编码为1:16
,不带引号。Ruby的YAML库(Psych)没有将其解释为字符串,而是以某种方式变成了Fixnum值4560
。我不知道如何解决这两方面的转换问题
对于我的用例,YAML中的每个值都应该是一个对象或字符串。因此,如果存在这样的选项,我可以告诉Perl YAML库引用所有值。或者有没有办法告诉Ruby YAML库将所有值解释为字符串?有什么想法吗
从逻辑上讲,更改任何一方的语言都不是一个选项
Perl:
红宝石:
Ruby代码将打印
4560
。其中一条评论解释了如何从1:16
获得4560
,它是1小时16分钟转换成秒的。嗯,好的。Ruby将所有YAML条目解释为字符串,除非它们合适。条目1:16
看起来与特殊格式匹配了一段时间,因此Ruby错误地解释了它
您需要强制Ruby将字段解释为字符串。有两种方法可以做到这一点。以下任一YAML输出应为您提供所需的结果:
abc: !str 1:16
abc: '1:16'
要生成此输出,请尝试以下Perl代码:
my $foo={'abc'=>'!str 1:16'};
my $foo={'abc'=>"'1:16'"};
更新:
我能够使用以下代码在Perl和Ruby之间传递数据:
Perl:
红宝石:
结果使用起来比加载文件返回的简单散列要复杂一些,但看起来它至少像预期的那样解析了文件。正在使用的解析器中有一个bug。它似乎认为
1:16
是某种时间(因为4560是一小时16分钟内的秒数),但我发现没有任何东西可以验证这种解释
最好的解决方案是使用一个没有bug的解析器
- YAML::XS使用的
,据说有Ruby绑定libyaml
- YAML::Syck使用的
,据说有Ruby绑定libsyck
$ perl -e'
use YAML::Syck qw( Dump );
local $YAML::Syck::SingleQuote = 1;
print(Dump({abc=>"1:16"}));
'
---
"abc": '1:16'
(不知道我之前怎么错过了这个选项!)根据,1:16
是一个六进制(60进制)格式的整数
另请参见,其中说明:
使用“:”允许以60为基数表示整数,这便于时间和角度值
Ruby,Psych中包含的Yaml解析器(错误地说,1:16
应该是71–Psych代码似乎认为所有这些值都将以a:b:c
的形式出现,但regex没有强制执行)。Perl发射器(至少是我测试过的YAML::XS)无法识别这种格式,因此在编写文件时不会引用字符串。XS确实识别并引用了一些整数,但不是全部。XS也不能识别Psych所能识别的许多其他格式(例如日期)
(似乎是sexagesimal格式。)
Psych在解析方面有很大的灵活性–YAML.load\u file
只是一个用于常见用例的简单接口
您可以使用Psych的parse
方法创建yaml的树表示,然后使用自定义ScalarScanner
将其转换为Ruby数据结构(该对象将特定格式的字符串转换为适当的Ruby类型):
require('yaml'))
类MyScalarScanner
这与使用YAML.load_file
时发生的过程基本相同,只是它使用自定义的scanner类
类似的替代方法是打开ScalarScanner
,用定制的方法替换tokenize
方法。这将允许您使用更简单的load_file
接口,但需要注意猴子补丁类:
class Psych::ScalarScanner
别名:orig_tokenize:tokenize
def标记化字符串
如果字符串=~/^[-+]?[0-9][0-9\]*(:[0-5]?[0-9]),则返回字符串+$/
原始标记化字符串
结束
结束
foo=YAML.load_文件'test.YAML'
请注意,这些示例仅考虑具有类似
1:16
格式的值。根据Perl程序发出的内容,您可能还需要覆盖其他模式。您可能特别想了解的是sexagesimal浮点(例如,1:16.44
)。能否提供一些YAML数据示例以及用于解码的Ruby和Perl代码?4560是一小时16分钟内的秒数(假设没有闰秒)。生成的YAML文件是什么样子的?@bta,由于它是由“--\nabc:1:16\n”
生成的,所以我可以说,问题出在Ruby方面。您是否可以使用另一个解析器?它正确地生成abc:'!str 1:16'
和abc:'1:16'
。我相信这两种格式都不会在Ruby中产生正确的结果。1:16
与您链接的文档中列出的任何格式都不匹配。@ikegami-它只与格式匹配了一段时间,尽管该页面上的有限示例使用了更复杂的示例。Ruby为日期和时间对象提供了许多可能的输出格式选项,YAML解析器似乎正在标记任何可能是日期的内容。我的Perl技能非常生疏,因此您可能需要调整它以在fo中获得YAML输出
my $foo={'abc'=>'!str 1:16'};
my $foo={'abc'=>"'1:16'"};
use YAML::XS qw(DumpFile);
my $foo={'abc'=>'1:16'};
DumpFile('test.yaml',$foo);
require 'yaml'
foo=YAML.parse_file('test.yaml')
foo['abc'].value
=> "1:16"
foo['abc'].value.class
=> String
$ perl -e'
use YAML::Syck qw( Dump );
local $YAML::Syck::SingleQuote = 1;
print(Dump({abc=>"1:16"}));
'
---
"abc": '1:16'