如何从 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 => valuevariable : 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 输出:

--- (?-xism:^spam): 鸡蛋 红色 数字: - 5 - 8

不过,我不知道 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 数据结构?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Perl 快速访问许多大型 CSV 文件中的数据?

如何将数据从 Perl 发送到 Python

如何通过工作表名称在 Perl 中读取 Excel 文件

如何从python 3中的url读取html

如何从 Perl 创建或读取 OpenOffice 电子表格?

如何删除从perl读取sql文件时附加的特殊字符