如何从 Python 中读取 Perl 数据结构?
Posted
技术标签:
【中文标题】如何从 Python 中读取 Perl 数据结构?【英文标题】:How can I read Perl data structures from Python? 【发布时间】:2010-09-28 05:52:07 【问题描述】:我经常看到人们使用 Perl 数据结构来代替配置文件;即一个单独的文件,仅包含:
%config = (
'color' => 'red',
'numbers' => [5, 8],
qr/^spam/ => 'eggs'
);
使用纯 Python 将这些文件的内容转换为 Python 等效数据结构的最佳方法是什么?目前我们可以假设没有要评估的真正表达式,只有结构化数据。
【问题讨论】:
使用编码语言作为你的配置文件格式是难以置信的......风险很大。确信您知道这是您的应用程序的最佳方式,并且没有什么比 Yaml、XML 或平面文件更好的了。 是的,我不建议任何人选择这样做——这是我继承的东西。 :-) 琐事:这不是 Perl 本身支持的。所有哈希键都被字符串化; Perl 中的哈希键只能使用字符串。您必须使用像this 这样的模块来解析这样的哈希工作,并且由于Perl 积极地打乱了键值对的顺序,因此这样的命令的输出可能定义不明确。如果您的配置文件 必须 是可执行的,那么您不妨编写一个适当的 perl 模块,其中包含一个 sub 和一堆return 'eggs' if $url =~ qr/^spam/;
行...
【参考方案1】:
不确定用例是什么。这是我的假设:您将进行一次从 Perl 到 Python 的一次性转换。
Perl 有这个
%config = (
'color' => 'red',
'numbers' => [5, 8],
qr/^spam/ => 'eggs'
);
在 Python 中是
config =
'color' : 'red',
'numbers' : [5, 8],
re.compile( "^spam" ) : 'eggs'
所以,我猜是一堆 RE 来代替
%variable = (
和 variable =
);
和
variable => value
与 variable : value
qr/.../ =>
与 re.compile( r"..." ) : value
但是,Python 的内置 dict
并没有将正则表达式用作哈希键做任何不寻常的事情。为此,您必须编写自己的 dict
子类,并覆盖 __getitem__
以单独检查 REGEX 键。
class PerlLikeDict( dict ):
pattern_type= type(re.compile(""))
def __getitem__( self, key ):
if key in self:
return super( PerlLikeDict, self ).__getitem__( key )
for k in self:
if type(k) == self.pattern_type:
if k.match(key):
return self[k]
raise KeyError( "key %r not found" % ( key, ) )
这是使用类似 Perl 的 dict 的示例。
>>> pat= re.compile( "hi" )
>>> a = pat : 'eggs' # native dict, no features.
>>> x=PerlLikeDict( a )
>>> x['b']= 'c'
>>> x
<_sre.SRE_Pattern object at 0x75250>: 'eggs', 'b': 'c'
>>> x['b']
'c'
>>> x['ji']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in __getitem__
KeyError: "key 'ji' not found"
>>> x['hi']
'eggs'
【讨论】:
数据结构嵌套时会变得更加复杂,这可能需要某种递归解析器。 如果它确实变得更复杂,我们必须更详细地查看用例。这种事情似乎是一次性的手动转换的事情。但也许不是。无法从问题中看出实际用例是什么。 这个总体思路只需稍加调整即可发挥作用。 (正则表达式转换有点棘手。) (通过正则表达式转换,我的意思是正则表达式被用作哈希中的键——将它们更改为 re.compile 形式并非易事。) “正则表达式被用作哈希中的键”这是什么意思?【参考方案2】:我只是把 Perl 数据结构变成别的东西。没有看到实际文件,我的解决方案可能没有做一些额外的工作。
如果文件中只有一个变量声明(因此,最后没有 1;
,等等),将 %config
转换为 YAML 非常简单:
perl -MYAML -le 'print YAML::Dump( do shift )' filename
do
返回它评估的最后一个东西,所以在这个小代码中它返回哈希键值对列表。诸如 YAML::Dump 之类的东西喜欢使用引用,因此它们可以得到有关顶层结构的提示,因此我通过用花括号将 do
括起来将其变为哈希引用。对于你的例子,我会得到这个 YAML 输出:
不过,我不知道 Python 会喜欢那个字符串化的正则表达式。你真的有一个正则表达式的键吗?我很想知道它是如何作为配置的一部分使用的。
如果文件中有多余的东西,生活会更加艰难。可能有一种非常聪明的方法可以解决这个问题,但我使用了相同的想法,只是硬编码了我想要的变量名。
我在 CPAN.pm 模块使用的 Perl 数据结构上尝试了这个,看起来效果很好。唯一丑陋的是它提供的变量名的先验知识。既然您已经看到 Perl 代码中的配置错误,请避免在 Python 代码中犯同样的错误。 :)
YAML:
perl -MYAML -le 'do shift; print YAML::Dump( $CPAN::Config )' MyConfig.pm
JSON:
perl -MJSON::Any -le 'do shift; my $j = JSON::Any->new; print $j->objToJson( $CPAN::Config )' MyConfig.pm
或
# suggested by JF Sebastian
perl -MJSON -le 'do shift; print to_json( $CPAN::Config )' MyConfig.pm
XML::Simple 效果不佳,因为它将所有内容都视为属性,但也许有人可以对此进行改进:
perl -MXML::Simple -le 'do shift; print XMLout( $CPAN::Config )' MyConfig.pm
【讨论】:
对于 OP myconfig.pm 它可能是perl -MJSON -E'do shift; say to_json \%config' myconfig.pm
。但是 Python 不会理解 '(?-xism:^spam)' 正则表达式。
这是一个非常好的解决方案。试图获取除 perl 之外的任何东西来解析 perl 很快就会变成大量工作。您甚至可以将整个内容包装在 python 中的函数调用中,它只是一个 subprocess.Popen 和 json.load 调用。【参考方案3】:
我也找到了PyPerl,但它似乎没有得到维护。我想这就是我正在寻找的东西——一个对 Perl 进行一些基本解释并将结果作为 Python 对象传递的模块。一个因过于复杂而死的 Perl 解释器会很好。 :-)
【讨论】:
PyPerl 不是纯 Python。它是一个用 C 语言编写的 python 扩展模块。 要点——我想我正在寻找类似 PyPerl 的东西,它是用纯 Python 实现的。 :-)【参考方案4】:是否需要使用纯 Python?如果没有,您可以在 Perl 中加载它并将其转换为 YAML 或 JSON。然后使用 PyYAML 或类似的东西在 Python 中加载它们。
【讨论】:
我想使用纯 Python,但这仍然很有帮助。 :)以上是关于如何从 Python 中读取 Perl 数据结构?的主要内容,如果未能解决你的问题,请参考以下文章