如何从字符串中选择数字,直到出现第一个非数字字符?

时间:2016-07-15 07:47:16

标签: python python-3.x

我有一组字符串,如:

"0"
"90/100"
None
"1-5%/34B-1"
"-13/7"

我想将它们转换为整数(或None),以便我从头开始选择数字并停在第一个非数字字符处。因此上述数据将成为:

0
90
None
1
None

我尝试过类似下面的代码,但遇到了多个问题,例如当ValueError只是空字符串时,int(new_n)行导致new_n。即使没有这个,代码看起来很可怕:

def pick_right_numbers(old_n):
    new_n = ''
    numbers = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
    if old_n is None:
        return None
    else:
        for n in old_n:
            if n in numbers:
                new_n += n
            else:
                return int(new_n)
        if new_n:
            return int(new_n)
        else:
            return None

有人可以用这个推动我朝着正确的方向前进吗?

4 个答案:

答案 0 :(得分:0)

>>> import re
>>> s = ["0", "90/100", None, "1-5%/34B-1", "-13/7"]
>>> [int(c) if c else None for c in (re.sub('([0-9]*).*', r'\1', str(x)) for x in s)]
[0, 90, None, 1, None]

如何运作

我们有两个列表推导。除了初始数字之外,内部从列表s的元素中删除所有内容:

>>> list(re.sub('([0-9]*).*', r'\1', str(x)) for x in s)
['0', '90', '', '1', '']

外部列表理解将这些字符串(如果非空)转换为整数或以其他方式转换为None

>>> [int(c) if c else None for c in ('0', '90', '', '1', '')]
[0, 90, None, 1, None]

替代方案:使用takewhile

根据Bakuriu的评论,我们可以使用intertools.takewhile代替re.sub

>>> from itertools import takewhile
>>> [int(c) if len(c) else None for c in (''.join(takewhile(str.isdigit, x or "")) for x in s)]
[0, 90, None, 1, None]

对原始代码的修改

或者,我们可以修改原始代码:

def pick_right_numbers(old_n):
    if old_n is None:
        return None
    else:
        new_n = ''
        for n in old_n:
            if not n.isdigit():
                break
            new_n += n 
        return int(new_n) if len(new_n) else None

此代码生成输出:

>>> [pick_right_numbers(x) for x in s]
[0, 90, None, 1, None]

答案 1 :(得分:0)

执行此操作的基本方法是:

input_list = ["0", "90/100", None,  "1-5%/34B-1", "-13/7"]
char_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
output_list = []

for input_str in input_list:

    if isinstance(input_str, str):
        i = 0
        for input_char in input_str:
            if input_char in char_list:
                i += 1
            else:
                break
    else:
        i = 0

    if i:
        output = int(input_str[0:i])
    else:
        output = None

    output_list.append(output)

但是有很多变种。如果它是一个你每天重复10.000次以上的功能,那么一些性能分析会很聪明地考虑替代方案。

编辑:考虑python 2 vs 3中的字符串可能是明智的(参见What is the difference between isinstance('aaa', basestring) and isinstance('aaa', str)?

edit2:看看Bakuriu的解决方案如何简化这一点 - >

from itertools import takewhile
input_list = ["0", "90/100", None,  "1-5%/34B-1", "-13/7"]
output_list = []
for input_str in input_list:
    text = ''.join(takewhile(str.isdigit, input_str or ""))        
    output_list.append(int(text) if text else None)

(所以我认为他应该将其作为诚实的最佳答案;)

答案 2 :(得分:0)

这是你要找的东西吗?

import re
data = ['0', '90/100', None, '1-5%/34B-1', '-13/7']

def pick_right_numbers(old_n):
    if old_n is None:
        return None
    else:
        digits = re.match("([0-9]*)",old_n).groups()[0]
        if digits.isdigit():
            return int(digits)
        else:
            return None

for string in data:
    result = pick_right_numbers(string)
    if result is not None:
        print("Matched section is : {0:d}".format(result))

它使用re(模式匹配)来检测字符串开头的数字块(匹配只匹配字符串的开头,搜索会在字符串中的任何位置找到一个块)。 它检查匹配,确认匹配是数字(否则最后一个数据元素匹配,但是是空字符串)并将其转换为整数以返回。

答案 3 :(得分:0)

有多种方法可以检查对象是否为数字。例如,请参阅this answer

但是你只需要一次检查一个字符,所以你的方法实际上很好。该阵列将永久保存在缓存中,因此可以快速扫描。

请注意,您可以以更好的方式编写它:

if n in "0123456789":

另一种可能性,可能是最快的,是检查范围,通过ASCII表示将它们视为数值(使用数字在该表示中是连续的,并且按照您期望的顺序):

zero = ord('0')
nine = ord('9')
for n in old_n:
   nn = ord(n) 
   if (nn >= zero) and (nn <= nine):

当然,最优雅的方式是调用本地isdigit();你节省了所有的混乱,并使你的意图完全清楚。 请注意,它可能比您要求的更多 - 是根据Unicode的数字。但你不太可能遇到这种情况。另请注意,由于这个原因,它可能比您的实现更慢

请注意,您还需要在循环中检查new_n == ''!不重复自己的最好方法是,如果

,就不要再退出决赛了
def pick_right_numbers(old_n):
    new_n = ''
    if old_n is None:
        return None
    else:
        for n in old_n:
            if n.isdigit():
                new_n += n
            else:
                break
        if new_n:
            return int(new_n)
        else:
            return None

当然,如果你需要速度,你可能不得不改变方法,因为你在循环中增长一个向量。但是,如果这是对你有意义的逻辑,只有在这是程序的瓶颈时才会使它复杂化。