将由字母和数字组成的字符串拆分为多个部分

时间:2014-04-04 12:54:02

标签: python regex string

我有一个字符串,由字符串和数字(​​整数或浮点数)的交替字符串组成,这些字符串具有任意长度,我希望将它分成几个部分,每个部分都有最大可能的大小,这样一部分就会由字符串或(表示a)字符串组成。

我不需要考虑特殊形式的数字,例如指数,十六进制等;只是简单的浮点或整数。

一些例子:

>>> split("")
()
>>> split("p")
('p',)
>>> split("2")
('2',)
>>> split("a2b3")
('a', '2', 'b', '3')
>>> split("a2.1b3")
('a', '2.1', 'b', '3')
>>> split("a.1b3")
('a', '.1', 'b', '3')

但是,以下调用应该引发一些错误:

>>> split(3)
>>> split("a0.10.2")
>>> split("ab.c")

我的第一次尝试是使用re.split。但是,这种尝试很天真,如果我写这些字母,它就不会保存分隔符:

>>> re.split("[a-z]", "a.1b3")
['', '.1', '3']

我的第二次尝试是使用itertools.groupby。问题在于它并不关心数字的形式,例如:

>>> islowalpha = labmda s: str.isalpha(s) and str.islower(s)
>>> [''.join(g) for _, g in itertools.groupby("a0.10.2b", islowalpha)]  # should raise
['a', '0.10.2', 'b']

注意:我不关心输出的形式,只要它是可迭代的。

注意:我已阅读this,但我无法使解决方案适应我的问题。主要区别在于我只需要允许接受的数字,而不是简单的数字和点列表。

4 个答案:

答案 0 :(得分:2)

import re

def split_gen(x):
    for f, s in re.findall(r'([\d.]+)|([^\d.]+)', x):
        if f:
            float(f)
            yield f
        else:
            yield s

def split(x):
    '''
    >>> split("")
    ()
    >>> split("p")
    ('p',)
    >>> split("2")
    ('2',)
    >>> split("a2b3")
    ('a', '2', 'b', '3')
    >>> split("a2.1b3")
    ('a', '2.1', 'b', '3')
    >>> split("a.1b3")
    ('a', '.1', 'b', '3')
    >>> split(3)
    Traceback (most recent call last):
    ...
    TypeError: expected string or buffer
    >>> split("a0.10.2")
    Traceback (most recent call last):
    ...
    ValueError: could not convert string to float: '0.10.2'
    >>> split("ab.c")    
    Traceback (most recent call last):
    ...
    ValueError: could not convert string to float: '.'
    '''
    return tuple(split_gen(x))

if __name__ == '__main__':
    import doctest
    doctest.testmod()

答案 1 :(得分:1)

使用re.subitertools.cycle进行一些游戏:

def split(s):
    res = []

    def replace(matchobj):
        res.append(matchobj.group(0))
        return ''

    letter = re.compile('^([a-z]+)')
    number = re.compile('^(\.\d|\d+\.\d+|\d+)')

    if letter.match(s):
        c = itertools.cycle([letter, number])
    else:
        c = itertools.cycle([number, letter])

    for op in c:
        mods = op.sub(replace, s)
        if len(s) == len(mods):
            return
        elif not mods:
            return res
        s = mods

基本思路 - 创建两个交替的re模式,并尝试将输入字符串与它们匹配。

包含一些示例的演示:

>>> split("2")
['2']
>>> split("a2b3")
['a', '2', 'b', '3']
>>> split("a.1b3")
['a', '.1', 'b', '3']
>>> split("a0.10.2")
>>> split("ab.c")

答案 2 :(得分:0)

问题在于你的问题的前提是合情合理的。如何区分浮点数与任意字符串?有很多方法可以解释。例如,
    0.10.2 这可能意味着0.1,0.2。或0,.10,.2
如果数字是多少呢?     27.6734.98? 您需要指定首先是什么类型的数字和格式。例如:每个数字只有小数点后的一位数。

答案 3 :(得分:-1)

import re

string = 'a.2b3c4.5d'

REG_STR = r'([a-zA-Z])|(\.\d+)|(\d+\.\d+)|(\d+)'
matches = [m.group() for m in re.finditer(REG_STR, string) if re.finditer(REG_STR, string)]