2014-04-04 3 views
3

나는 임의의 길이의 소문자로 된 문자와 숫자 (정수 또는 부동 소수점)가 교대로 반복되는 문자열을 가지고 있는데, 각 부분으로 나누고 싶습니다. 부분이 문자열 또는 (문자열을 나타내는 문자열) 숫자로 구성 될 수 있도록 가능한 최대 크기.글자와 숫자로 구성된 문자열을 부분으로 나눕니다.

지수, 16 진수 등과 같은 특별한 형태의 숫자는 고려할 필요가 없습니다. 단순한 부동 소수점 또는 정수.

몇 가지 예 :

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

그러나, 다음의 호출은 몇 가지 오류가 발생한다 : 내 첫 번째 시도는 re.split을 사용했다

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

. 그러나이 시도는 매우 순진하고, 나는이 편지를 만들 경우에는 구분 기호를 저장하지 않습니다 : 내 두 번째 시도 itertools.groupby을 사용했다

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

합니다.

>>> 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을 읽었지만 문제를 해결할 수 없습니다. 가장 큰 차이점은 숫자와 포인트의 단순한 목록이 아닌 허용 가능한 숫자 만 허용해야한다는 것입니다.

+0

' "a0.10.2"'뭐가 문제 그것은' "a2.1b3"'에서 다른 이유는 무엇입니까? –

+0

'0.10.2'는 숫자가 아니기 때문에; 숫자와 하위 문자열을 번갈아 사용하는 하위 문자열도 아닙니다. – Bach

+0

알 수없는 '교대'제한이 있습니다. –

답변

0

문제는 귀하의 질문 전제가 그럴듯하다는 것입니다. 어떻게 임의의 문자열에서 수레를 구별 할 수 있습니까? 해석 할 수있는 방법이 많이 있습니다. 예 :
0.10.2 이는 0.1, 0.2를 의미 할 수 있습니다. 또는 0, .10, .2
숫자가 27.6734.98이면? 번호의 종류와 형식을 먼저 지정해야합니다. 예 : 모든 숫자는 십진수 옆에 한 자리 숫자 만 있습니다. re.subitertools.cycle 지키기

+0

나는 당신의 비판에 동의하지 않습니다. '27.6734.98'과 같은 문자열은 대소 문자가 다른 알파 문자열과 숫자 문자열을 교대로 구성하지 않기 때문에 오류가 발생한다고 명시 적으로 언급했습니다. – Bach

+0

비평처럼 들리면 죄송합니다.내 말은 숫자 부분이 '27 .6734.98 '과 같은 것일 때입니다. 따라서 완전한 예제 입력은 'ab27.6734.98h'와 같을 수 있습니다. – IsThatYou

1

비트 :

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") 
-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)] 
+0

Erk, 읽지 않는 것. 정규식은''(a-zA-Z) | (\ d \) | (\ d + \. \ d +) | (\ d +)이어야합니다. '' – Toadeeza

+0

여러분이 제안한 답변으로 게시물을 편집하십시오. – jww

1
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() 
관련 문제