如何让所有字符都变成一个数字?

How to get all characters upto a number?

我有如下字符串

>>> s1
'this_is-a.string-123-with.number'
>>> s2
'this_is-a123.456string-123-with.number'
>>> s3
'one-0more-str.999'

需要在拆分后获取所有数字(不是字母数字)之前的所有内容,因此从 s1 获取 this_is-a.string-,从 s2 获取 this_is-a123.456string-,从 s3 获取 one-0more-str.

>>> for a in re.split('-|_|\.',s2):
...    if a.isdigit():
...       r=re.split(a,s2)[0]
...       break
>>> print(r)
# expected: this_is-a123.456string-
# got: this_is-a

上面这段代码适用于s1,但不适用于s2,因为123匹配s2中的a123,应该有更好的pythonic方式吗?

更多信息:

s3为例,当我们用-_.作为分隔符时,999是我们唯一得到的所有数字,所以一切之前是需要打印的 one-0more-str. ,如果我们以 s2 为例,用 dash 或 underbar 或 dot 作为分隔符分割后, 123 将是 all number ( isdigit),所以得到 this_is-a123.456string- 之前的所有内容,所以如果输入字符串是 this_1s-a-4.test,输出应该是 this_1s-a-,因为 4 是拆分后的全数。

不确定它是否适用于所有情况,但您可以尝试:

for a in re.split('-|_|\.',s2).reverse():
    if a.isdigit():
        r=re.rsplit(a,s2)[0]
        break
print(r)

这将适用于您的示例案例:

def fn(s):
    return re.match("(.*?[-_.]|^)\d+([-_.]|$)", s).group(1)

^$分别匹配字符串的开头和结尾,.*?中的?进行非贪婪匹配。)

更多案例:

>>> fn("111")
""

>>> fn(".111")
"."

>>> fn(".1.11")
"."

你可能还想想想如果没有全数组你想得到什么:

>>> fn("foobar")

这适用于您的示例

代码

def parse(s):
  """ Splits on successive digits, 
      then takes everything up to last split on digits """
  return ''.join(re.split(r'(\d+)', s)[:-2])

测试

使用指定的字符串

for t in ['this_is-a.string-123-with.number',
          'this_is-a123.456string-123-with.number',
          'one-0more-str.999']:
    print(f'{parse(t)}')

输出

this_is-a.string-
this_is-a123.456string-
one-0more-str.

说明

字符串

s = 'this_is-a123.456string-123-with.number'

拆分数字组

re.split(r'(\d+)', s)
Out: ['this_is-a', '123', '.', '456', 'string-', '123', '-with.number']

省略拆分中的最后两项

re.split(r'(\d+)', s)[:-2] # [:-2] slice dropping last two items of list
Out: ['this_is-a', '123', '.', '456', 'string-']

将列表加入字符串

''.join(re.split(r'(\d+)', s)[:-2]) # join items
Out: this_is-a123.456string-

如果我理解正确,您可以使用单个正则表达式来获取所需的值:

import re
s1='this_is-a.string-123-with.number'
s2='this_is-a123.456string-123-with.number'
s3='one-0more-str.999'

# matches any group that is in between "all numbers"...
regex = re.compile('(.*[-\._])\d+([-\._].*)?')  

m = regex.match(s1)
print(m.groups())

m = regex.match(s2)
print(m.groups())

m = regex.match(s3)
print(m.groups())

当你运行这个结果如下:

('this_is-a.string-', '-with.number')
('this_is-a123.456string-', '-with.number')
('one-0more-str.', None)

如果您只对第一组感兴趣,您只能使用:

>>> print(m.group(1))
one-0more-str.

如果要过滤没有第二组的情况:

>>> print([i for i in m.groups() if i])
['one-0more-str.']