본문 바로가기

개발하자

Python에서 문자열의 단위에서 숫자 구분

반응형

Python에서 문자열의 단위에서 숫자 구분

나는 2GB, 17ft 등과 같은 단위의 숫자가 포함된 문자열을 가지고 있다. 나는 유닛에서 번호를 분리하여 두 개의 다른 문자열을 만들고 싶다. 때때로, 그것들 사이에 빈 공간(예: 2GB)이 있고 분할('' ')을 사용하여 그것을 하는 것은 쉽다.

그들이 함께 있을 때(예: 2GB), 나는 숫자 대신에 글자를 찾을 때까지 모든 문자를 테스트했다.

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

더 좋은 방법이 있을까요?

감사해요.




정규식을 사용하여 문자열을 그룹으로 나눌 수 있습니다:

>>> import re
>>> p = re.compile('(\d+)\s*(\w+)')
>>> p.match('2GB').groups()
('2', 'GB')
>>> p.match('17 ft').groups()
('17', 'ft')



정규 표현을 사용하는 것은 어떨까요

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




정규식을 사용하여 확인할 내용을 그룹화해야 합니다:

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))

구문 분석할 내용에 따라 정규식을 변경합니다. 정규 표현이 익숙하지 않다면 훌륭한 튜토리얼 사이트입니다.




도움이 될 수 있음:

>>> 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), '')



이 작업에는 다음과 같은 정규 표현을 사용합니다:

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 패턴에서, "흰색 공간"을 의미하고, "자리"를 의미하며, 공백이 아닌 공간을 의미하며, "앞의 0 이상"을 의미하고, "앞의 1 이상"을 의미하며, 괄호는 일치 객체에 대한 호출에 의해 반환되는 "캡처 그룹"을 포함한다. (지정된 문자열이 패턴과 일치하지 않는 경우 없음, 즉 선택적 공백, 한 자리 이상의 숫자, 선택적 공백, 한 자리 이상의 공백 문자입니다.




정규 표현.

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"와 단위 접두사를 구별하기에는 너무 어렵다)를 제공하고, 그 뒤에 단위와 공백을 선택적으로 제공한다.

경기를 많이 하실 분들은 이용하시면 됩니다.




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



첫 번째 숫자가 아닌 문자를 찾을 때 루프를 벗어날 수 있습니다

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()



>>> s="17GB"
>>> ind=map(str.isalpha,s).index(True)
>>> num,suffix=s[:ind],s[ind:]
>>> print num+":"+suffix
17:GB



이것은 정규식보다 조금 더 관대해야 하는 접근법을 사용한다. 참고: 이는 게시된 다른 솔루션보다 성능이 좋지 않습니다.

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()



과학적 표기법 이 정규식은 과학적 표기법에 있을 수 있는 숫자를 구문 분석하는 데 잘 작동하며 scanf에 대한 최근 파이썬 문서를 기반으로 합니다:

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



아래 정규식 패턴을 사용해 보십시오. 첫 번째 그룹(어떤 방식으로든 번호에 대한 scanf() 토큰)은 remodule에 대한 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



이러한 종류의 파서는 이미 다음에 통합되어 있습니다:

핀트(Pint)는 물리량(숫자 값과 측정 단위의 곱)을 정의, 작동 및 조작하기 위한 파이썬 패키지이다. 그것은 그것들 사이의 산술 연산과 다른 단위와의 변환을 허용한다.

와 함께 설치할 수 있습니다.

그런 다음 문자열을 구문 분석하고 원하는 값('규모')과 해당 단위를 얻을 수 있습니다:

>>> from pint import UnitRegistry
>>> ureg = UnitRegistry()
>>> size = ureg('2GB')
>>> size.m
2
>>> size.u
<Unit('gigabyte')>
>>> size.to('GiB')
<Quantity(1.86264515, 'gibibyte')>
>>> length = ureg('17ft')
>>> length.m
17
>>> length.u
<Unit('foot')>
>>> length.to('cm')
<Quantity(518.16, 'centimeter')>



불행하게도, 이전 코드들 중 어떤 것도 내 상황에서 제대로 작동하지 않았다. 나는 다음과 같은 코드를 개발했다. 코드 뒤의 아이디어는 모든 숫자가 숫자나 점으로 끝나는 것이다.

def splitValUnit(s):

    s = s.replace(' ', '')
    lastIndex = len(s) - 1
    i = lastIndex
    for i in range(lastIndex, -1, -1):
        if (s[i].isdigit() or s[i] == '.'):
            break
        
    i = i + 1

    value = 0
    unit = ''
    try:
        value = float(s[:i])
        unit = s[i:]
    except:
        pass

    return {'value': value, 'unit': unit}

print(splitValUnit('7'))             #{'value': 7.0, 'unit': ''}
print(splitValUnit('+7'))            #{'value': 7.0, 'unit': ''}
print(splitValUnit('7m'))            #{'value': 7.0, 'unit': 'm'}
print(splitValUnit('27'))            #{'value': 27.0, 'unit': ''}
print(splitValUnit('7.'))            #{'value': 7.0, 'unit': ''}
print(splitValUnit('2GHz'))          #{'value': 2.0, 'unit': 'GHz'}
print(splitValUnit('+2.e-10H'))      #{'value': 2e-10, 'unit': 'H'}
print(splitValUnit('2.3e+4 MegaOhm'))#{'value': 23000.0, 'unit': 'MegaOhm'}
print(splitValUnit('-4.'))           #{'value': -4.0, 'unit': ''}
print(splitValUnit('e mm'))          #{'value': 0, 'unit': ''}
print(splitValUnit(''))              #{'value': 0, 'unit': ''}

반응형