7

我有包含数字及其单位的字符串,例如 2GB、17 英尺等。我想将数字与单位分开并创建 2 个不同的字符串。有时,它们之间有一个空格(例如 2 GB),使用 split(' ') 很容易做到这一点。

当它们在一起时(例如 2GB),我会测试每个字符,直到找到一个字母,而不是一个数字。

s='17GB'
number=''
unit=''
for c in s:
    if c.isdigit():
        number+=c
    else:
        unit+=c

有更好的方法吗?

谢谢

4

12 回答 12

11

当您找到第一个非数字字符时,您可以跳出循环

for i,c in enumerate(s):
    if not c.isdigit():
        break
number = s[:i]
unit = s[i:].lstrip()

如果你有负数和小数:

numeric = '0123456789-.'
for i,c in enumerate(s):
    if c not in numeric:
        break
number = s[:i]
unit = s[i:].lstrip()
于 2010-02-10T21:26:47.693 回答
7

您可以使用正则表达式将字符串分组:

>>> import re
>>> p = re.compile('(\d+)\s*(\w+)')
>>> p.match('2GB').groups()
('2', 'GB')
>>> p.match('17 ft').groups()
('17', 'ft')
于 2010-02-10T21:03:21.440 回答
3

tokenize能够帮助:

>>> import StringIO
>>> s = StringIO.StringIO('27GB')
>>> for token in tokenize.generate_tokens(s.readline):
...   print token
... 
(2, '27', (1, 0), (1, 2), '27GB')
(1, 'GB', (1, 2), (1, 4), '27GB')
(0, '', (2, 0), (2, 0), '')
于 2010-02-10T21:04:24.247 回答
2

您应该使用正则表达式,将您想要找出的内容组合在一起:

import re
s = "17GB"
match = re.match(r"^([1-9][0-9]*)\s*(GB|MB|KB|B)$", s)
if match:
  print "Number: %d, unit: %s" % (int(match.group(1)), match.group(2))

根据您要解析的内容更改正则表达式。如果您不熟悉正则表达式,这里有一个很棒的教程网站。

于 2010-02-10T21:03:52.700 回答
2
s='17GB'
for i,c in enumerate(s):
    if not c.isdigit():
        break
number=int(s[:i])
unit=s[i:]
于 2010-02-10T21:10:43.297 回答
2
>>> s="17GB"
>>> ind=map(str.isalpha,s).index(True)
>>> num,suffix=s[:ind],s[ind:]
>>> print num+":"+suffix
17:GB
于 2010-02-11T01:39:02.017 回答
2

这使用了一种比正则表达式更宽容的方法。注意:这不像发布的其他解决方案那样高效。

def split_units(value):
    """
    >>> split_units("2GB")
    (2.0, 'GB')
    >>> split_units("17 ft")
    (17.0, 'ft')
    >>> split_units("   3.4e-27 frobnitzem ")
    (3.4e-27, 'frobnitzem')
    >>> split_units("9001")
    (9001.0, '')
    >>> split_units("spam sandwhiches")
    (0, 'spam sandwhiches')
    >>> split_units("")
    (0, '')
    """
    units = ""
    number = 0
    while value:
        try:
            number = float(value)
            break
        except ValueError:
            units = value[-1:] + units
            value = value[:-1]
    return number, units.strip()
于 2015-05-06T20:39:32.270 回答
0

如何使用正则表达式

http://python.org/doc/1.6/lib/module-regsub.html

于 2010-02-10T21:03:48.083 回答
0

对于这个任务,我肯定会使用正则表达式:

import re
there = re.compile(r'\s*(\d+)\s*(\S+)')
thematch = there.match(s)
if thematch:
  number, unit = thematch.groups()
else:
  raise ValueError('String %r not in the expected format' % s)

在 RE 模式中,\s表示“空白”,\d表示“数字”,\S表示非空白;*表示“前面的 0 个或多个”,+表示“前面的 1 个或多个”,括号括起来“捕获组”,然后由groups()对匹配对象的调用返回。(thematch如果给定的字符串没有,则为 None对应于模式:可选空格,然后是一个或多个数字,然后是可选空格,然后是一个或多个非空格字符)。

于 2010-02-10T21:07:45.147 回答
0

一个正则表达式。

import re

m = re.match(r'\s*(?P<n>[-+]?[.0-9])\s*(?P<u>.*)', s)
if m is None:
  raise ValueError("not a number with units")
number = m.group("n")
unit = m.group("u")

这将为您提供一个带有可选符号的数字(整数或定点;很难从单位前缀中区分科学记数法的“e”),后跟单位,以及可选的空格。

re.compile()如果您要进行很多比赛,则可以使用。

于 2010-02-10T21:08:55.593 回答
0

科学记数法这个正则表达式非常适合我解析可能采用科学记数法的数字,并且基于最近关于 scanf 的 python 文档: https ://docs.python.org/3/library/re.html#simulating-扫描

units_pattern = re.compile("([-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?|\s*[a-zA-Z]+\s*$)")
number_with_units = list(match.group(0) for match in units_pattern.finditer("+2.0e-1 mm"))
print(number_with_units)
>>>['+2.0e-1', ' mm']

n, u = number_with_units
print(float(n), u.strip())
>>>0.2 mm
于 2017-02-07T15:32:08.773 回答
0

试试下面的正则表达式模式。第一组(任何方式的数字的 scanf() 标记)直接从 re 模块的 python 文档中提取。

import re
SCANF_MEASUREMENT = re.compile(
    r'''(                      # group match like scanf() token %e, %E, %f, %g
    [-+]?                      # +/- or nothing for positive
    (\d+(\.\d*)?|\.\d+)        # match numbers: 1, 1., 1.1, .1
    ([eE][-+]?\d+)?            # scientific notation: e(+/-)2 (*10^2)
    )
    (\s*)                      # separator: white space or nothing
    (                          # unit of measure: like GB. also works for no units
    \S*)''',    re.VERBOSE)
'''
:var SCANF_MEASUREMENT:
    regular expression object that will match a measurement

    **measurement** is the value of a quantity of something. most complicated example::

        -666.6e-100 units
'''

def parse_measurement(value_sep_units):
    measurement = re.match(SCANF_MEASUREMENT, value_sep_units)
    try:
        value = float(measurement[0])
    except ValueError:
        print 'doesn't start with a number', value_sep_units
    units = measurement[5]

    return value, units
于 2017-02-26T22:37:19.557 回答