2012-09-26 13 views
5

PerlとRubyの間でYAMLを介して交換されるデータに問題があります。私は1:16のようなnumber:numberのようないくつかの値を持っています。PerlとRuby間のYAMLデータ交換の問題

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); 

ルビー:

require('yaml') 
foo=YAML.load_file('test.yaml') 
puts(foo['abc']) 

Rubyコードが4560を印刷します。コメントの1つは45601:16からどうやって得るかを考え出したもので、1時間16分が秒に変換されています。ああ、大丈夫。

+1

デコードに使用しているRubyコードとPerlコードのサンプルYAMLをいくつか挙げてください。 – Schwern

+3

4560は1時間16分の秒数です(うるう秒がないと仮定します)。 – ikegami

+1

生成されたYAMLファイルはどのように見えますか? – bta

答えて

5

Yaml 1.1 specによると、1:16は六十進法の整数(ベース60)の形式です。

を使用して:言う

も参照http://yaml.org/type/int.htmlは、「:」時間と角度の値のために便利である、ベース60の整数を表現することができます。

ルビー、サイコ、recognises this format and converts the value into an integerに含まYAMLパーサ(誤っ、1:16は71であるshoud - 心理コードは、すべてのこのような値は、フォームa:b:cであろうことasumeようだが、正規表現はそれを強制しません)。 Perlエミッター(少なくとも私がテストしたYAML :: XS)はこのフォーマットを認識しないので、ファイルを書くときに文字列を引用しません。 YAML :: XS では一部の整数を認識して引用しますが、すべてではありません。 YAML :: XSは、Psychが行う他の多くのフォーマット(日付など)も認識しません。

(。これは、60進形式has been removed from the Yaml 1.2 specことが表示されます)

サイコは、その構文解析における柔軟性のかなりの取引を可能にする - YAML.load_fileは、一般的なユースケースのためだけのシンプルなインターフェースです。

Psychのparseメソッドを使用してyamlのツリー表現を作成し、これをカスタムScalarScanner(特定のフォーマットの文字列を適切なRubyタイプに変換するオブジェクト)を使用して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インタフェースを使用することができますが、サルのパッチクラスについての通常の警告となりますこれらの例のみ1:16のような形式で考慮値にとること

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' 

注意。あなたのPerlプログラムが放射するものによっては、他のパターンも上書きする必要があります。あなたが見たいと思うかもしれない1つは、60進数の浮動小数点(例えば、1:16.44)です。

-4

ruby​​は、a handful of special formatsに収まらない限り、すべてのYAMLエントリを文字列として解釈します。エントリ1:16は、それが時間のための特別なフォーマットにマッチするように見えるので、Rubyはそれを誤って解釈しています。

Rubyにフィールドを文字列として解釈させる必要があります。これを行うには2つの方法があります。次のPerlコードを試してみてください、この出力を生成するには

abc: !str 1:16 
abc: '1:16' 

:以下YAML出力のどちらかは、あなたが望む結果を与える必要があります

my $foo={'abc'=>'!str 1:16'}; 
my $foo={'abc'=>"'1:16'"}; 

を更新: 私が合格することができました

たPerl:

use YAML::XS qw(DumpFile); 
my $foo={'abc'=>'1:16'}; 
DumpFile('test.yaml',$foo); 
0123以下のコードを使用して、PerlとRubyの間でデータ

ルビー:

require 'yaml' 
foo=YAML.parse_file('test.yaml') 
foo['abc'].value 
=> "1:16" 
foo['abc'].value.class 
=> String 

結果は、もう少し複雑な単純なハッシュよりも、そのload_fileリターンを使用するのですが、予想通り、それは、少なくともファイルを解析ているように見えます。

+0

これは 'abc: '!str 1:16''と 'abc: '"' 1:16 '' ''を正しく生成します。私はどちらもRubyで正しい結果を生み出すとは思わない。 – ikegami

+0

'1:16'はあなたがリンクした文書に記載されている形式のいずれとも一致しません。 – ikegami

+0

@ ikegami-シンプルな書式に一致しますが、そのページの限られた例ではより複雑なサンプルが使用されます。 Rubyには、日付と時刻のオブジェクトのための多くの出力形式オプションがあります.YAMLパーサは日付でも可能性のあるものにはフラグを立てているようです。私のPerlのスキルは非常に錆びているので、YAMLの出力をリストにした形式で出力するには、それを微調整する必要があります。 – bta

1

使用しているパーサーにバグがあります。 1:16はある種の時間だと思えるようです(4560は1時間16分の秒数です)。しかし、その解釈を検証するものは何も見つかりません。

最良の解決策は、バグではないパーサーを使用することです。

  • libyamlは、YAML :: XSで使用されていると思われるRubyバインディングです。
  • libsyckは、YAML :: Syckが使用していると思われるRubyバインディングです。

文字列が常に引用される(または少なくとも時間として扱われる)ときにYAMLを生成する方法もあります。

YAML::Syckには、これを行うオプションがあります。

$ perl -e' 
    use YAML::Syck qw(Dump); 
    local $YAML::Syck::SingleQuote = 1; 
    print(Dump({abc=>"1:16"})); 
' 
--- 
"abc": '1:16' 

(私は以前、このオプションを逃した方法がわからない!)

+0

私はYAML :: XSを試しました。同じ問題があります。 YAML :: Syckは私を非常に緊張させます。ここにはYAML :: Syck- のCPANページからの引用があります "このモジュールには既知の多くの問題があり、半永久的に2007年以来維持されています。問題が発生した場合は、 Gitでリリース準備が整ったパッチをアップしてください。 " Rubyのドキュメントは基本的に同じことを言います。 –

+0

私はあなたがYAML :: XSを使うべきだとは言わなかった - 実際にあなたが言ったことによると - 私はRubyでlibyamlまたはlibsyckを使ってみるべきだと言いました。 – ikegami

関連する問題