문자열을 대문자로 분할


94

주어진 문자 집합이 발생하기 전에 문자열을 분할하는 비단뱀적인 방법 은 무엇입니까 ?

예를 들어, 'TheLongAndWindingRoad' 대문자 (아마도 첫 번째 문자 제외)가 나올 때마다 나누고 ['The', 'Long', 'And', 'Winding', 'Road'].

편집 :에서 그것은 또한 즉, 하나의 발생을 분할해야 'ABC'내가 얻을 싶습니다 ['A', 'B', 'C'].

답변:


137

불행히도 파이썬에서는 너비가 0 인 일치분할 할 수 없습니다 . 그러나 re.findall대신 사용할 수 있습니다 .

>>> import re
>>> re.findall('[A-Z][^A-Z]*', 'TheLongAndWindingRoad')
['The', 'Long', 'And', 'Winding', 'Road']
>>> re.findall('[A-Z][^A-Z]*', 'ABC')
['A', 'B', 'C']

13
이 경우 첫 번째 대문자 앞에 모든 문자가 삭제됩니다. 'theLongAndWindingRoad'[ '권선' '롱', '그리고', '길']에서 초래
마크 Schulder

14
@MarcSchulder :이 경우가 필요 '[a-zA-Z][^A-Z]*'하면 정규식으로 사용 하십시오.
knub

대문자없이 똑같이 할 수 있습니까?
Laurent Cesaro 2018

2
낮은 낙타 케이스 단어를 나누기 위해print(re.findall('^[a-z]+|[A-Z][^A-Z]*', 'theLongAndWindingRoad'))
hard_working_ant

32

다음은 대체 정규식 솔루션입니다. 문제는 "분할하기 전에 각 대문자 앞에 공백을 삽입하는 방법"으로 다시 표현할 수 있습니다.

>>> s = "TheLongAndWindingRoad ABC A123B45"
>>> re.sub( r"([A-Z])", r" \1", s).split()
['The', 'Long', 'And', 'Winding', 'Road', 'A', 'B', 'C', 'A123', 'B45']

이것은 대부분의 다른 솔루션이 그렇지 않은 모든 비 공백 문자를 보존하는 이점이 있습니다.


\ 1 앞의 공간이 왜 작동하는지 설명해 주시겠습니까? 분할 방법 때문입니까 아니면 정규식과 관련된 것입니까?
Lax_Sam

분할 구분 기호의 기본값은 공백 문자열입니다
CIsForCookies

20
>>> import re
>>> re.findall('[A-Z][a-z]*', 'TheLongAndWindingRoad')
['The', 'Long', 'And', 'Winding', 'Road']

>>> re.findall('[A-Z][a-z]*', 'SplitAString')
['Split', 'A', 'String']

>>> re.findall('[A-Z][a-z]*', 'ABC')
['A', 'B', 'C']

rexeg를 변경 하기 "It'sATest"위해 분할 ["It's", 'A', 'Test']하려면"[A-Z][a-z']*"


+1 : 먼저 ABC가 작동하도록합니다. 나는 또한 지금 내 대답을 업데이트했습니다.
Mark Byers

>>> re.findall ( '[AZ] [az] *', "경제의 약 70 %") -----> [ 'It', 'Economy']
ChristopheD

@ChristopheD. OP는 알파벳이 아닌 문자를 처리하는 방법을 말하지 않습니다.
John La Rooy

1
사실이지만이 현재 정규식 방식 drops은 대문자로 시작하지 않는 모든 일반 (일반 알파) 단어 도 마찬가지 입니다. 나는 그것이 OP의 의도라고 의심합니다.
ChristopheD

8

@ChristopheD 솔루션의 변형

s = 'TheLongAndWindingRoad'

pos = [i for i,e in enumerate(s+'A') if e.isupper()]
parts = [s[pos[j]:pos[j+1]] for j in xrange(len(pos)-1)]

print parts

2
좋은 것-이것은 라틴어가 아닌 문자에서도 작동합니다. 여기에 표시된 정규식 솔루션은 그렇지 않습니다.
AlexVhr 2013

7

미리보기 사용 :

Python 3.7에서는 다음을 수행 할 수 있습니다.

re.split('(?=[A-Z])', 'theLongAndWindingRoad')

그리고 그것은 다음을 산출합니다 :

['the', 'Long', 'And', 'Winding', 'Road']

5
import re
filter(None, re.split("([A-Z][^A-Z]*)", "TheLongAndWindingRoad"))

또는

[s for s in re.split("([A-Z][^A-Z]*)", "TheLongAndWindingRoad") if s]

1
이 필터는 완전히 불필요하며 캡처 그룹과 직접 정규식 분할을 통해 구매 당신에게 아무것도 : [s for s in re.compile(r"([A-Z][^A-Z]*)").split( "TheLongAndWindingRoad") if s]제공['The', 'Long', 'And', 'Winding', 'Road']
SMCI

1
@smci :이 사용법은 filter조건이있는 목록 이해와 동일합니다. 그것에 반대하는 것이 있습니까?
Gabe

1
조건이있는 목록 이해로 대체 될 수 있다는 것을 알고 있습니다. 방금 해당 코드를 게시 한 다음 복사했기 때문입니다. 여기에 세 가지 이유가있는 지능형리스트가 바람직하다 : a)는 읽기 쉬운 관용구 : 지능형리스트가 더 파이썬 관용구하고 명확 왼쪽에서 오른쪽으로보다 읽기 filter(lambdaconditionfunc, ...)파이썬 3) B를 filter()반복자를 반환합니다. 따라서 그들은 완전히 동등하지 않을 것입니다. c) 저도 filter()느리다고 생각합니다
smci

4
src = 'TheLongAndWindingRoad'
glue = ' '

result = ''.join(glue + x if x.isupper() else x for x in src).strip(glue).split(glue)

1
이것이 문제에 대한 좋은 해결책 인 이유에 대한 설명을 추가해 주시겠습니까?
Matas Vaitkevicius 2014

죄송 해요. 마지막 단계를 잊었습니다
user3726655

간결하고 비단뱀 적이며 자명 한 것 같습니다.

4

더 나은 대답 문자열을 대문자로 끝나지 않는 단어로 나누는 것입니다. 이것은 문자열이 대문자로 시작하지 않는 경우를 처리합니다.

 re.findall('.[^A-Z]*', 'aboutTheLongAndWindingRoad')

예:

>>> import re
>>> re.findall('.[^A-Z]*', 'aboutTheLongAndWindingRoadABC')
['about', 'The', 'Long', 'And', 'Winding', 'Road', 'A', 'B', 'C']

2

대체 솔루션 (명시 적 정규식을 싫어하는 경우) :

s = 'TheLongAndWindingRoad'

pos = [i for i,e in enumerate(s) if e.isupper()]

parts = []
for j in xrange(len(pos)):
    try:
        parts.append(s[pos[j]:pos[j+1]])
    except IndexError:
        parts.append(s[pos[j]:])

print parts

1

정규식이없고 원하는 경우 연속 대문자를 유지할 수있는 기능

def split_on_uppercase(s, keep_contiguous=False):
    """

    Args:
        s (str): string
        keep_contiguous (bool): flag to indicate we want to 
                                keep contiguous uppercase chars together

    Returns:

    """

    string_length = len(s)
    is_lower_around = (lambda: s[i-1].islower() or 
                       string_length > (i + 1) and s[i + 1].islower())

    start = 0
    parts = []
    for i in range(1, string_length):
        if s[i].isupper() and (not keep_contiguous or is_lower_around()):
            parts.append(s[start: i])
            start = i
    parts.append(s[start:])

    return parts

>>> split_on_uppercase('theLongWindingRoad')
['the', 'Long', 'Winding', 'Road']
>>> split_on_uppercase('TheLongWindingRoad')
['The', 'Long', 'Winding', 'Road']
>>> split_on_uppercase('TheLongWINDINGRoadT', True)
['The', 'Long', 'WINDING', 'Road', 'T']
>>> split_on_uppercase('ABC')
['A', 'B', 'C']
>>> split_on_uppercase('ABCD', True)
['ABCD']
>>> split_on_uppercase('')
['']
>>> split_on_uppercase('hello world')
['hello world']

1

이것은 more_itertools.split_before도구 로 가능합니다 .

import more_itertools as mit


iterable = "TheLongAndWindingRoad"
[ "".join(i) for i in mit.split_before(iterable, pred=lambda s: s.isupper())]
# ['The', 'Long', 'And', 'Winding', 'Road']

또한 단일 항목을 분할해야합니다. 즉, 'ABC'I 'd like to get ['A', 'B', 'C'].

iterable = "ABC"
[ "".join(i) for i in mit.split_before(iterable, pred=lambda s: s.isupper())]
# ['A', 'B', 'C']

more_itertools수동 구현을 제거하는 모든 원래 itertools 레시피 구현을 포함하여 60 개 이상의 유용한 도구가 포함 된 타사 패키지입니다 .


0

정규식 또는 열거를 사용하지 않는 다른 방법 :

word = 'TheLongAndWindingRoad'
list = [x for x in word]

for char in list:
    if char != list[0] and char.isupper():
        list[list.index(char)] = ' ' + char

fin_list = ''.join(list).split(' ')

너무 많은 메서드를 연결하거나 읽기 어려울 수있는 긴 목록 이해를 사용하지 않고 더 명확하고 간단하다고 생각합니다.


0

사용하는 또 다른 방법 enumerateisupper()

암호:

strs = 'TheLongAndWindingRoad'
ind =0
count =0
new_lst=[]
for index, val in enumerate(strs[1:],1):
    if val.isupper():
        new_lst.append(strs[ind:index])
        ind=index
if ind<len(strs):
    new_lst.append(strs[ind:])
print new_lst

산출:

['The', 'Long', 'And', 'Winding', 'Road']

0

게시물을 읽을 때 떠오른 것을 공유합니다. 다른 게시물과 다릅니다.

strs = 'TheLongAndWindingRoad'

# grab index of uppercase letters in strs
start_idx = [i for i,j in enumerate(strs) if j.isupper()]

# create empty list
strs_list = []

# initiate counter
cnt = 1

for pos in start_idx:
    start_pos = pos

    # use counter to grab next positional element and overlook IndexeError
    try:
        end_pos = start_idx[cnt]
    except IndexError:
        continue

    # append to empty list
    strs_list.append(strs[start_pos:end_pos])

    cnt += 1

0

Pythonic 방법은 다음과 같습니다.

"".join([(" "+i if i.isupper() else i) for i in 'TheLongAndWindingRoad']).strip().split()
['The', 'Long', 'And', 'Winding', 'Road']

re / re2를 피하면서 유니 코드에 잘 작동합니다.

"".join([(" "+i if i.isupper() else i) for i in 'СуперМаркетыПродажаКлиент']).strip().split()
['Супер', 'Маркеты', 'Продажа', 'Клиент']

-1

주어진 모든 대문자 'L'을 빈 공간과 그 문자 "L"로 바꿉니다. 목록 이해를 사용하여이를 수행하거나 다음과 같이이를 수행하는 함수를 정의 할 수 있습니다.

s = 'TheLongANDWindingRoad ABC A123B45'
''.join([char if (char.islower() or not char.isalpha()) else ' '+char for char in list(s)]).strip().split()
>>> ['The', 'Long', 'A', 'N', 'D', 'Winding', 'Road', 'A', 'B', 'C', 'A123', 'B45']

기능별로 선택하는 경우 방법은 다음과 같습니다.

def splitAtUpperCase(text):
    result = ""
    for char in text:
        if char.isupper():
            result += " " + char
        else:
            result += char
    return result.split()

주어진 예의 경우 :

print(splitAtUpperCase('TheLongAndWindingRoad')) 
>>>['The', 'Long', 'A', 'N', 'D', 'Winding', 'Road']

그러나 우리가 대문자로 문장을 분할하는 대부분의 경우, 일반적으로 대문자의 연속 스트림 인 약어를 유지하려는 경우가 일반적입니다. 아래 코드가 도움이 될 것입니다.

def splitAtUpperCase(s):
    for i in range(len(s)-1)[::-1]:
        if s[i].isupper() and s[i+1].islower():
            s = s[:i]+' '+s[i:]
        if s[i].isupper() and s[i-1].islower():
            s = s[:i]+' '+s[i:]
    return s.split()

splitAtUpperCase('TheLongANDWindingRoad')

>>> ['The', 'Long', 'AND', 'Winding', 'Road']

감사.


@MarkByers 나는 누군가가 내 대답을 왜 투표했는지 모르겠지만 나를 위해 그것을 살펴보기를 바랍니다. 귀하의 의견에 감사드립니다.
Samuel Nde
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.