我在通过 YAML 在 Perl 和 Ruby 之间交换数据时遇到问题。我有一些看起来像数字:数字的值,例如 1:16
。
Perl 的 YAML 库(Tiny 和 XS)将其编码为 1:16
,不带引号。 Ruby 的 YAML 库 (Psych) 不会将其解释为字符串,而是以某种方式变成 Fixnum 值 4560
。我不知道如何在任何一方解决这个转换问题。
我用例的 YAML 中的每个值都应该是一个对象或字符串。因此,如果存在这样的选项,我可以告诉 Perl YAML 库引用所有值。或者有什么方法可以告诉 Ruby YAML 库将所有值解释为字符串?有任何想法吗?
从逻辑上讲,改变任何一方的语言都不是一种选择。
Perl:
use YAML::XS qw(DumpFile);
my $foo={'abc'=>'1:16'};
DumpFile('test.yaml',$foo);
ruby :
require('yaml')
foo=YAML.load_file('test.yaml')
puts(foo['abc'])
Ruby 代码将打印 4560
。其中一条评论说明了如何从 1:16
得到 4560
,即 1 小时 16 分钟转换为秒。嗯,好的。
最佳答案
根据Yaml 1.1 spec , 1:16
是一个六十进制(以 60 为底)格式的整数。
另见 http://yaml.org/type/int.html ,它说:
Using “:” allows expressing integers in base 60, which is convenient for time and angle values.
Ruby、Psych 中包含的 Yaml 解析器,recognises this format and converts the value into an integer (错误地,1:16
应该是 71——Psych 代码似乎假设所有这些值都将采用 a:b:c
的形式,但正则表达式并不强制执行)。 Perl 发射器(至少我测试过的 YAML::XS)不识别这种格式,所以在写入文件时不引用字符串。 YAML::XS 确实识别并引用了一些整数,但不是全部。 YAML::XS 也无法识别 Psych 可以识别的许多其他格式(例如日期)。
(好像是六十进制格式has been removed from the Yaml 1.2 spec。)
Psych 在其解析中提供了相当大的灵 active ——YAML.load_file
只是常见用例的简单接口(interface)。
您可以使用 Psych 的 parse
方法创建 yaml 的树表示,然后使用自定义 ScalarScanner
(这是将特定格式的字符串转换为适当的 Ruby 类型的对象):
require('yaml')
class MyScalarScanner < Psych::ScalarScanner
def tokenize string
#this is the same regexp as Psych uses to detect base 60 ints:
return string if string =~ /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+$/
super
end
end
tree = YAML::parse_file 'test.yaml'
foo = Psych::Visitors::ToRuby.new(MyScalarScanner.new).accept tree
这与使用 YAML.load_file
时发生的过程基本相同,只是它使用了自定义的扫描器类。
类似的替代方法是打开 ScalarScanner
并将 tokenize
方法替换为自定义方法。这将允许您使用更简单的 load_file
接口(interface),但带有关于猴子修补类的常见警告:
class Psych::ScalarScanner
alias :orig_tokenize :tokenize
def tokenize string
return string if string =~ /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+$/
orig_tokenize string
end
end
foo = YAML.load_file 'test.yaml'
请注意,这些示例仅考虑格式为 1:16
的值。根据您的 Perl 程序发出的内容,您可能还需要覆盖其他模式。您可能特别想看看的一个是六十进制 float (例如 1:16.44
)。
关于ruby - Perl 和 Ruby 之间的 YAML 数据交换问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12610187/