Регулярное выражение в Python - PullRequest
1 голос
/ 15 октября 2010

У меня есть следующая строка:

schema(field1, field2, field3, field4 ... fieldn)

Мне нужно преобразовать строку в объект с атрибутом имени как schema и именами полей как другим атрибутом, который является списком.

Как мне сделать это в Python с помощью регулярного выражения?

Ответы [ 3 ]

5 голосов
/ 15 октября 2010

Вы ищете что-то подобное?

>>> s = 'schema(field1, field2, field3, field4, field5)'
>>> name, _, fields = s[:-1].partition('(')
>>> fields = fields.split(', ')
>>> if not all(re.match(r'[a-z]+\d+$', i) for i in fields):
    print('bad input')

>>> sch = type(name, (object,), {'attr': fields})
>>> sch
<class '__main__.schema'>
>>> sch.attr
['field1', 'field2', 'field3', 'field4', 'field5']
1 голос
/ 15 октября 2010

Регулярные выражения для подобных вещей, вероятно, нуждаются в тестах:

import unittest

import re

# Verbose regular expression!  http://docs.python.org/library/re.html#re.X
p = r"""

(?P<name>[^(]+)         # Match the pre-open-paren name.
\(                      # Open paren
(?P<fields>             # Comma-separated fields
    (?:
        [a-zA-Z0-9_-]+
        (?:,\ )         # Subsequent fields must separated by space and comma
    )*
    [a-zA-Z0-9_-]+       # At least one field. No trailing comma or space allowed.
)

\)                      # Close-paren
"""

# Compiled for speed!
cp = re.compile(p, re.VERBOSE)

class Foo(object):
    pass


def validateAndBuild(s):
    """Validate a string and return a built object.
    """
    match = cp.search(s)
    if match is None:
        raise ValueError('Bad schema: %s' % s)

    schema = match.groupdict()
    foo = Foo()
    foo.name = schema['name']
    foo.fields = schema['fields'].split(', ')

    return foo



class ValidationTest(unittest.TestCase):
    def testValidString(self):
        s = "schema(field1, field2, field3, field4, fieldn)"

        obj = validateAndBuild(s)

        self.assertEqual(obj.name, 'schema')

        self.assertEqual(obj.fields, ['field1', 'field2', 'field3', 'field4', 'fieldn'])

    invalid = [
        'schema field1 field2',
        'schema(field1',
        'schema(field1 field2)',
        ]

    def testInvalidString(self):
        for s in self.invalid:
            self.assertRaises(ValueError, validateAndBuild, s)


if __name__ == '__main__':
    unittest.main()
0 голосов
/ 15 октября 2010

Вы можете использовать что-то вроде (в двух раундах, потому что Python Re не поддерживает вложенный захват (спасибо SilentGhost за указание на это)):

pattern = re.compile("^([a-z]+)\(([a-z,]*)\)$")

ret = pattern.match(s)

if ret==None:
    ...
else:
    f = ret.groups()
    name = f[0]
    args = f[1]

    arg_pattern = re.compile("^([a-z]+)(,[a-z]+)*$")

    ret2 = arg_pattern.match(args)

    # same checking as above
    if (ret2==None):
         ...
    else:
         args_f = ret2.groups()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...