Как я могу прочитать структуры данных Perl из Python? - PullRequest
11 голосов
/ 23 декабря 2008

Я часто видел, как люди используют структуры данных Perl вместо файлов конфигурации; то есть одинокий файл, содержащий только:

%config = (
    'color' => 'red',
    'numbers' => [5, 8],
    qr/^spam/ => 'eggs'
);

Как лучше всего преобразовать содержимое этих файлов в эквивалентные Python структуры данных, используя чистый Python? В настоящее время мы можем предположить, что нет реальных выражений для оценки, только структурированные данные.

Ответы [ 4 ]

18 голосов
/ 23 декабря 2008

Требуется ли использование чистого Python? Если нет, вы можете загрузить его в Perl и преобразовать в YAML или JSON. Затем используйте PyYAML или что-то подобное, чтобы загрузить их в Python.

14 голосов
/ 24 декабря 2008

Я бы просто превратил структуру данных Perl во что-то другое. Не видя реального файла, может быть, есть дополнительная работа, которую мое решение не выполняет.

Если в файле есть только одно объявление переменной (то есть, нет 1; в конце и т. Д.), Может быть действительно просто превратить ваш %config в YAML:

perl -MYAML -le 'print YAML::Dump( { do shift } )' filename 

do возвращает последнее, что он вычислил, поэтому в этом небольшом коде он возвращает список пар ключ-значение хеш-функции. Такие вещи, как YAML :: Dump, любят работать со ссылками, поэтому они получают подсказку о структуре верхнего уровня, поэтому я превращаю это в ссылку на хэш, окружая do фигурными скобками. Для вашего примера я бы получил вывод YAML:

---
(?-xism:^spam): eggs
color: red
numbers:
  - 5
  - 8

Хотя я не знаю, как Python понравится это строковое регулярное выражение. У вас действительно есть ключ, который является регулярным выражением? Мне было бы интересно узнать, как это используется как часть конфигурации.


Если в файле есть что-то лишнее, жизнь немного сложнее. Вероятно, есть действительно умный способ обойти это, но я использовал ту же идею, но просто жестко закодировал имя переменной, которое хотел.

Я пробовал это на структуре данных Perl, которую использует модуль CPAN.pm, и, похоже, все получилось хорошо. Единственное уродство - это предварительное знание имени переменной, которую она предоставляет. Теперь, когда вы увидели ошибку конфигурации в коде 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
7 голосов
/ 23 декабря 2008

Не уверен, каков вариант использования. Вот мое предположение: вы собираетесь выполнить однократное преобразование из 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'
0 голосов
/ 24 декабря 2008

Я также нашел PyPerl , но, похоже, он не поддерживается. Я думаю, что-то вроде этого - то, что я искал - модуль, который сделал некоторую базовую интерпретацию Perl и передал результат как объект Python. Интерпретатор Perl, который умер от чего-то слишком сложного, будет в порядке. : -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...