문자열을 여러 단어 경계 구분 기호가있는 단어로 분할


671

내가하고 싶은 일은 상당히 일반적인 작업이지만 웹에서 참조를 찾지 못했습니다. 문장 부호가있는 텍스트가 있고 단어 목록을 원합니다.

"Hey, you - what are you doing here!?"

해야한다

['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

그러나 파이썬 str.split()은 하나의 인수로만 작동하므로 공백으로 나누면 구두 점이있는 모든 단어가 있습니다. 어떤 아이디어?



6
파이썬 str.split()도 전혀 논증없이 작동합니다
— Ivan Vinogradov

답변:


468

정규식이 정당화되는 경우 :

import re
DATA = "Hey, you - what are you doing here!?"
print re.findall(r"[\w']+", DATA)
# Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

2
감사. 그래도 여전히 관심이 있습니다-이 모듈에 사용 된 알고리즘을 어떻게 구현할 수 있습니까? 그리고 왜 문자열 모듈에 나타나지 않습니까?
— ooboo 2016 년

29
정규 표현식은 처음에는 어려울 수 있지만 매우 강력합니다. 정규식 '\ w +'는 "한 번 이상 반복되는 단어 문자 (az 등)"를 의미합니다. 파이썬 정규 표현식에 대한 하우투가 있습니다 : amk.ca/python/howto/regex
— RichieHindle

324
이것은 질문에 대한 답변이 아닙니다. 이 특정 상황에서 작동하는 다른 질문에 대한 답변입니다. 마치 누군가가 "왼쪽 회전을 어떻게합니까?"라고 물었고 가장 인기있는 답변은 "다음 3 번 오른쪽 회전을하세요"입니다. 특정 교차로에서 작동하지만 필요한 답변을 제공하지 않습니다. 아이러니하게도, 대답은 이다 에 re, 그냥 findall. 아래 답변 re.split()은 우수합니다.
— Jesse Dhillon

4
@JesseDhillon은 "일련의 단어 문자로 구성된 모든 하위 문자열을 취합니다"및 "단어가 아닌 문자로 구성된 모든 하위 문자열에 분리"는 문자 그대로 동일한 연산을 표현하는 다른 방식입니다. 왜 당신이 어느 쪽의 대답을 우월하다고 부르는지 모르겠습니다.
— Mark Amery

4
@TMWP 다음 apostophe 수단 그런 단어 don't라기로 분리되는 것보다, 하나의 단어로 취급 don하고 t.
— RichieHindle

574

re.split ()

re.split (패턴, 문자열 [, maxsplit = 0])

패턴 발생으로 문자열을 분할합니다. 캡처 괄호를 패턴에 사용하면 패턴의 모든 그룹의 텍스트도 결과 목록의 일부로 반환됩니다. maxsplit이 0이 아닌 경우 최대 maxsplit 분할이 발생하고 문자열의 나머지 부분이 목록의 최종 요소로 리턴됩니다. 비 호환성 노트 : 최초의 Python 1.5 릴리스에서는 maxsplit이 무시되었습니다. 이것은 이후 릴리스에서 수정되었습니다.

>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.']

13
이 솔루션은 밑줄로도 쉽게 분할 할 수 있다는 장점이 있습니다. findall 솔루션은 그렇지 않습니다. print re.split ( "\ W + | _", "Testing this_thing") 'yields : ['Testing ','this ' , 'thing']
— Emil Stenström

63
이제 경우에만 나는 차이 기억할 수 \w, \W, \s,와 \S. 깃발의 대문자가 그 의미를 뒤집어 야한다고 생각한 사람은 머리를 통해 쏠 필요가 있습니다.
— ArtOfWarfare

1
문자열 분할의 일반적인 사용 사례는 최종 결과에서 빈 문자열 항목을 제거하는 것입니다. 이 방법으로 그렇게 할 수 있습니까? re.split ( '\ W +', 'abc') 결과는 [ '', 'a', 'b', 'c', '']
— Scott Morken

3
@ArtOfWarfare shift키 를 사용 하여 반대 작업 을하는 것이 일반적 입니다. 재실행에 대한 실행 ctrl+z취소 대 ctrl+shift+z. 따라서 shift w또는 W반대의 경우 w입니다.
— Frank Vel

1
이 답변은 맨 위에 있어야합니다. 질문 제목에 정확하게 답변하는 것은 유일합니다.
— Kranach

381

정규 표현식 없이이 작업을 수행하는 또 다른 빠른 방법은 다음과 같이 문자를 먼저 바꾸는 것입니다.

>>> 'a;bcd,ef g'.replace(';',' ').replace(',',' ').split()
['a', 'bcd', 'ef', 'g']

71
빠르고 더럽지 만 제 경우에는 완벽합니다. (분리기는 작고 알려진 세트였습니다)
— Andy Baker

7
특정 소형 마이크로 컨트롤러와 같은 RE 라이브러리에 액세스 할 수없는 경우에 적합합니다. :-)
— tu-Reinstate Monica-dor du

11
나는 이것이 RE보다 명시 적이라고 생각하기 때문에 일종의 멍청한 친절합니다. 때로는 모든 것에 대한 일반적인 해결책이 필요하지 않습니다
— Adam Hughes

대박. 다중 입력 상황에서 .split ()이 있었고 사용자가 입력을 공백으로 구분하고 쉼표가 아닌 경우를 포착해야했습니다. 나는 포기하고 다시 캐스트했지만 .replace () 솔루션이 머리에 못을 박았습니다. 감사.
— JayJay123

공백으로 나누고 싶지 않고 다른 문자로 나누고 싶을 때 오답을 얻습니다.
— Ahmed Amr

307

너무 많은 답변이지만 , 질문 제목 이 문자 그대로 요구하는 것을 효율적으로 수행하는 솔루션을 찾을 수 없습니다 (여러 가지 구분 기호로 나누기-대신 많은 답변이 단어가 아닌 다른 단어로 나뉘어 짐). 그래서 여기 제목의 질문에 대한 답변이 있습니다.이 질문은 파이썬의 표준적이고 효율적인 re모듈 에 의존 합니다 :

>>> import re  # Will be splitting on: , <space> - ! ? :
>>> filter(None, re.split("[, \-!?:]+", "Hey, you - what are you doing here!?"))
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

어디:

  • […]일치 한 분리기의 내부 상장,
  • \-정규 표현식에서이의 특별한 해석을 방지하기 위해 여기에있다 -(뿐만 문자 범위 표시기 A-Z)
  • 은 +하나 개 건너 뜁니다 이상 (는 감사를 생략 할 수있는 구분 기호를 filter(), 그러나 이것은 불필요하게 일치 구분 사이의 빈 문자열을 생산하는 것)하고,
  • filter(None, …) 선행 및 후행 구분 기호로 생성 될 수있는 빈 문자열을 제거합니다 (빈 문자열에는 잘못된 부울 값이 있으므로).

이 re.split()질문 제목 요청으로, 정확하게 "다수의 분리와 분열".

이 솔루션은 또한 다른 솔루션에서 발견되는 비 ASCII 문자 문제의 영향을받지 않습니다 ( ghostdog74의 답변에 대한 첫 번째 주석 참조 ).

이 re모듈은 파이썬 루프를 수행하고 "수동으로"테스트하는 것보다 훨씬 효율적입니다 (속도와 결정 성)!


3
"질문의 제목이 문자 그대로 요구하는 것을 효율적으로 수행하는 솔루션을 찾을 수 없습니다"-두 번째 답변은 5 년 전에 게시했습니다 : stackoverflow.com/a/1059601/2642204 .
— BartoszKP

17
이 대답은 여러 구분 기호 집합에서 구분 기호로 분리되지 않습니다. 대신 영숫자가 아닌 항목으로 나눕니다. 즉, 원래 포스터의 의도는 구두점을 제거하는 대신 단어 만 유지하는 데 동의합니다.
— Eric O Lebigot

EOL :이 답변은 여러 개의 단위로 나뉘어져 있다고 생각합니다. 밑줄과 같이 지정되지 않은 문자열에 영숫자가 아닌 문자를 추가하면 예상대로 분할되지 않습니다.
— GravityWell

@ GravityWell : 잘 모르겠습니다 : 구체적인 예를 들어 줄 수 있습니까?
— Eric O Lebigot

3
@EOL : 방금 당신의 의견 "이 답변은 나뉘 지 않습니다 ..."라는 말로 혼란스러워한다는 것을 깨달았습니다. "이것은"re.split 답변을 의미한다고 생각했지만, 이제는 gimel의 답변을 의미한다는 것을 알았습니다. 나는이 답변 (나는 내가 대답하고있는 답변)이 가장 좋은 답변이라고 생각합니다 :)
— GravityWell

56

정규식이없는 다른 방법

import string
punc = string.punctuation
thestring = "Hey, you - what are you doing here!?"
s = list(thestring)
''.join([o for o in s if not o in punc]).split()

8
이 솔루션은 실제로 허용 된 솔루션보다 낫습니다. ASCII 문자없이 작동합니다 "Hey, you - what are you doing here María!?". 허용 된 솔루션은 이전 예제에서 작동하지 않습니다.
— Christopher Ramírez 2018 년

4
나는 여기에 작은 문제가 있다고 생각합니다 ... 코드는 문장 부호로 구분 된 문자를 추가하여 분리하지 않습니다 ... 내가 틀리지 않으면 마지막 줄은 다음과 같아야합니다.''.join([o if not o in string.punctuation else ' ' for o in s]).split()
— cedbeu

정규식 라이브러리는 필요한 경우 문자에 대한 유니 코드 규칙을 허용하도록 만들 수 있습니다. 또한 이것은 허용 된 솔루션의 문제와 동일합니다. 현재와 같이 아포스트로피로 분할됩니다. 당신이 원할 수도 o for o in s if (o in not string.punctuation or o == "'")있지만 cedbeu의 패치를 추가하면 하나의 라이너에 비해 너무 복잡해집니다.
— Daniel H

여기 또 다른 문제가 있습니다. @cedbeu의 변경 사항을 고려하더라도 문자열이 비슷 "First Name,Last Name,Street Address,City,State,Zip Code"하고 쉼표로만 분할하려는 경우이 코드가 작동하지 않습니다 ,. 원하는 출력은 다음과 같습니다 ['First Name', 'Last Name', 'Street Address', 'City', 'State', 'Zip Code']대신에 우리가 무엇을 얻을 :['First', 'Name', 'Last', 'Name', 'Street', 'Address', 'City', 'State', 'Zip', 'Code']
— Akker 덴 스테판 반을

4
이 솔루션은 매우 비효율적입니다. 먼저 목록을 개별 문자로 분해 한 다음 원래 문자열의 각 단일 문자에 대해 문장 부호 문자 전체를 통과 한 다음 문자를 다시 조립 한 다음 다시 분할합니다. 이 "움직임"은 정규 표현식 기반 솔루션에 비해 매우 복잡합니다. 주어진 응용 프로그램에서 속도가 중요하지 않더라도 복잡한 솔루션이 필요하지 않습니다. 때문에 re모듈이 표준이며 가독성과 속도를 모두 제공이 삼해야하는 이유, 내가 볼 수 없습니다.
— Eric O Lebigot 2016 년

39

프로 팁 : string.translate파이썬이 가지고있는 가장 빠른 문자열 연산에 사용하십시오 .

증거 ...

먼저 느린 방법 (죄송합니다) :

>>> import timeit
>>> S = 'Hey, you - what are you doing here!?'
>>> def my_split(s, seps):
...     res = [s]
...     for sep in seps:
...         s, res = res, []
...         for seq in s:
...             res += seq.split(sep)
...     return res
... 
>>> timeit.Timer('my_split(S, punctuation)', 'from __main__ import S,my_split; from string import punctuation').timeit()
54.65477919578552

다음으로 re.findall()제안 된 답변에 따라 사용 합니다. 훨씬 더 빨리:

>>> timeit.Timer('findall(r"\w+", S)', 'from __main__ import S; from re import findall').timeit()
4.194725036621094

마지막으로 다음을 사용합니다 translate.

>>> from string import translate,maketrans,punctuation 
>>> T = maketrans(punctuation, ' '*len(punctuation))
>>> timeit.Timer('translate(S, T).split()', 'from __main__ import S,T,translate').timeit()
1.2835021018981934

설명:

string.translateC로 구현되며 파이썬의 많은 문자열 조작 함수와 달리 새 문자열을 생성 string.translate 하지 않습니다 . 따라서 문자열을 대체 할 수있는 속도만큼 빠릅니다.

이 마법을 수행하려면 변환 표가 필요하기 때문에 조금 어색합니다. maketrans()편의 기능을 사용하여 변환 표를 만들 수 있습니다 . 여기서의 목적은 원하지 않는 모든 문자를 공백으로 변환하는 것입니다. 일대일 대용품. 다시, 새로운 데이터가 생성되지 않습니다. 그래서 이것은 빠릅니다 !

다음으로, 우리는 good old를 사용 split()합니다. split()기본적으로 모든 공백 문자에서 작동하여 분할을 위해 그룹화합니다. 결과는 당신이 원하는 단어의 목록이 될 것입니다. 그리고이 접근법은 거의 4 배 빠릅니다 re.findall()!


4
여기에서 테스트를 수행했으며 유니 코드 patt = re.compile(ur'\w+', re.UNICODE); patt.findall(S)를 사용해야하는 경우 변환을 적용하기 전에 문자열을 인코딩하고 분할 후 목록의 각 항목을 디코딩하여 유니 코드로 돌아 가야하기 때문에 유니 코드를 사용해야하는 경우 변환보다 빠릅니다.
— 라파엘 S. Calsaverini

번역 구현을 한 단계 줄이면서 S가 다음과 같은 스플리터에 포함되지 않도록 할 수 있습니다.s.translate(''.join([(chr(i) if chr(i) not in seps else seps[0]) for i in range(256)])).split(seps[0])
— 호브

촬영하지 않았습니다. 사과와 오렌지를 비교하고 있습니다. ;) 파이썬 3의 내 솔루션은 여전히 ​​작동합니다 .P 다중 문자 구분 기호를 지원합니다. :) 새로운 문자열을 할당하지 않고 간단한 방법으로 시도하십시오. :) 그러나 사실, 내 것은 예를 들어 책이 아닌 명령 줄 매개 변수를 구문 분석하는 것으로 제한됩니다.
— pprzemek

"새 문자열을 생성하지 않습니다"라고 말하면 주어진 문자열에서 제대로 작동합니까? 파이썬 2.7로 테스트했으며 oroginal 문자열을 수정하지 않고 새로운 문자열을 반환합니다.
— Prokop Hapala

26

비슷한 딜레마가 있었고 're'모듈을 사용하고 싶지 않았습니다.

def my_split(s, seps):
    res = [s]
    for sep in seps:
        s, res = res, []
        for seq in s:
            res += seq.split(sep)
    return res

print my_split('1111  2222 3333;4444,5555;6666', [' ', ';', ','])
['1111', '', '2222', '3333', '4444', '5555', '6666']

1
나는 이것을 좋아한다. 참고로 구분 기호의 순서가 중요합니다. 그게 분명하다면 미안합니다.
— crizCraig 2016 년

2
re더 빠르고 분명한 모듈을 사용하지 않는 이유는 무엇입니까? (정규 표현식이 특히 명확하지는 않지만 더 짧고 직접적이므로)?
— Eric O Lebigot

13

먼저 정규식 또는 str.translate(...)기반 솔루션이 가장 성능이 우수 하다는 다른 사람들과 동의하고 싶습니다 . 유스 케이스의 경우이 기능의 성능은 중요하지 않으므로 해당 기준으로 고려한 아이디어를 추가하고 싶었습니다.

내 주요 목표는 다른 답변의 아이디어를 하나의 솔루션으로 일반화하여 정규 표현식 단어 이상을 포함하는 문자열에 사용할 수 있습니다 (즉, 문장 부호 문자의 명시 적 하위 세트를 허용하는 단어 단어를 허용하는 단어 목록).

모든 접근 방식에서 string.punctuation수동으로 정의 된 목록 대신 사용 을 고려할 수도 있습니다 .

옵션 1-하위

나는 지금까지 대답이 re.sub (...)을 사용하지 않는 것을보고 놀랐습니다 . 이 문제에 대한 간단하고 자연스러운 접근 방식을 찾으십시오.

import re

my_str = "Hey, you - what are you doing here!?"

words = re.split(r'\s+', re.sub(r'[,\-!?]', ' ', my_str).strip())

이 솔루션에서는 re.sub(...)내부에 대한 호출을 중첩 re.split(...)했지만 성능이 중요하면 외부에서 정규식을 컴파일하는 것이 도움이 될 수 있습니다. 사용 사례의 경우 그 차이는 크지 않았으므로 단순성과 가독성을 선호합니다.

옵션 2-str.replace

이것은 몇 줄 더 있지만 정규 표현식에서 특정 문자를 이스케이프 해야하는지 여부를 확인하지 않고도 확장 할 수 있다는 이점이 있습니다.

my_str = "Hey, you - what are you doing here!?"

replacements = (',', '-', '!', '?')
for r in replacements:
    my_str = my_str.replace(r, ' ')

words = my_str.split()

대신 str.replace를 문자열에 매핑하는 것이 좋았지 만 변경할 수없는 문자열로 수행 할 수 있다고 생각하지 않으며 문자 목록에 대한 매핑이 작동하는 동안 모든 문자에 대해 모든 교체를 실행합니다 과도하게 들린다. (편집 : 기능적인 예는 다음 옵션을 참조하십시오.)

옵션 3-functools.reduce

Python 2에서는 reducefunctools에서 가져 오지 않고 전역 네임 스페이스에서 사용할 수 있습니다.

import functools

my_str = "Hey, you - what are you doing here!?"

replacements = (',', '-', '!', '?')
my_str = functools.reduce(lambda s, sep: s.replace(sep, ' '), replacements, my_str)
words = my_str.split()

흠, 다른 방법을 사용하는 것입니다 str.translate-유니 코드 를 사용할 수는 없지만 다른 방법보다 빠를 가능성이 높으며 경우에 따라 좋을 수도 있습니다. replacements=',-!?'; import string; my_str = my_str.translate(string.maketrans(replacements, ' ' * len(replacements)))또한 여기에서는 튜플 또는 명부.
— MarSoft

@MarSoft 감사합니다! 나는 대답의 맨 위에 하나 언급했지만 기존 답변이 이미 잘 논의 했으므로 추가하지 않기로 결정했습니다.
— Taylor Edmiston

10
join = lambda x: sum(x,[])  # a.k.a. flatten1([[1],[2,3],[4]]) -> [1,2,3,4]
# ...alternatively...
join = lambda lists: [x for l in lists for x in l]

그런 다음 3 줄짜리가됩니다.

fragments = [text]
for token in tokens:
    fragments = join(f.split(token) for f in fragments)

설명

이것이 하스켈에서 List 모나드로 알려진 것입니다. 모나드의 기본 개념은 일단 "모나드에"있으면 무언가가 나올 때까지 "모나드에 머물러"있다는 것입니다. 예를 들어 Haskell에서 Python range(n) -> [1,2,...,n]함수를 List에 매핑한다고 가정합니다 . 결과가 List 인 경우 결과가 List에 추가되므로 다음과 같은 결과가 나타납니다.map(range, [3,4,1]) -> [0,1,2,0,1,2,3,0] . 이것을 map-append (또는 mappend, 또는 이와 비슷한 것)라고합니다. 여기서 아이디어는 당신이 적용하고 (토큰에서 쪼개는)이 작업을 가지고 있으며, 그렇게 할 때마다 결과를 목록에 결합한다는 것입니다.

이것을 함수로 추상화 tokens=string.punctuation하고 기본적으로 가질 수 있습니다 .

이 방법의 장점 :

  • 순진한 정규식 기반 접근 방식과 달리이 방법은 임의 길이의 토큰 (정규식을 사용하여 고급 구문으로 수행 할 수 있음)과 함께 작동 할 수 있습니다.
  • 귀하는 단순한 토큰으로 제한되지 않습니다. 각 토큰 대신 임의의 논리를 가질 수 있습니다. 예를 들어 "토큰"중 하나는 중첩 된 괄호가 어떤지에 따라 분리되는 함수일 수 있습니다.

깔끔한 Haskell 솔루션이지만 IMO는 파이썬에서 mappend없이 더 명확하게 작성할 수 있습니다.
— 임팔라 블라드

@Goose : 요점은 2-line 함수 map_then_append를 사용하여 문제를 2-liner로 만들 수 있으며 다른 많은 문제를 훨씬 쉽게 작성할 수 있다는 것입니다. 다른 솔루션의 대부분은 re파이썬이 아닌 정규식 모듈을 사용합니다 . 그러나 나는 내 대답하게 우아하고 간결 정말 bloaty 보이는 방법에 불만이되었습니다 ... 나는 편집이 ... 갈거야
— ninjagecko

이것은 파이썬에서 작성된대로 작동해야합니까? 내 fragments결과는 문자열의 문자 목록 (토큰 포함)입니다.
— Rick은 Monica

@ RickTeachey : python2와 python3 모두에서 작동합니다.
— ninjagecko

흠. 어쩌면 예제가 약간 모호 할 수도 있습니다. 나는이 질문에 코드를 시도 가지는 등 다양한 ways- 모든 종류의 fragments = ['the,string'], fragments = 'the,string'또는 fragments = list('the,string')그 중 어느 것도 올바른 출력을 생성하지 않습니다.
— Rick은 Monica를 지원합니다.

5

이 시도:

import re

phrase = "Hey, you - what are you doing here!?"
matches = re.findall('\w+', phrase)
print matches

이 인쇄됩니다 ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']


4

바꾸기를 두 번 사용하십시오.

a = '11223FROM33344INTO33222FROM3344'
a.replace('FROM', ',,,').replace('INTO', ',,,').split(',,,')

결과 :

['11223', '33344', '33222', '3344']

4

나는 re를 좋아 하지만 여기에없는 해결책은 다음과 같습니다.

from itertools import groupby
sep = ' ,-!?'
s = "Hey, you - what are you doing here!?"
print [''.join(g) for k, g in groupby(s, sep.__contains__) if not k]

sep .__ contains__ 는 'in'연산자가 사용하는 방법입니다. 기본적으로는

lambda ch: ch in sep

그러나 더 편리합니다.

groupby 는 문자열과 함수를 얻습니다. 함수의 값이 변경 될 때마다 새 그룹이 생성 될 때마다 해당 함수를 사용하여 문자열을 그룹으로 분할합니다. 따라서 sep .__ contains__ 가 정확히 필요한 것입니다.

groupby 는 일련의 쌍을 반환합니다. 여기서 pair [0]은 함수의 결과이고 pair [1]은 그룹입니다. 'if not k'를 사용하면 구분 기호로 그룹을 필터링합니다 ( separs 에서 sep .__ contains__ 의 결과 가 True이므로). 글쎄, 그게 다야. 이제 각 그룹이 단어 인 그룹 시퀀스가 ​​있습니다 (그룹은 실제로 반복 가능하므로 조인 을 사용 하여 문자열로 변환합니다).

이 솔루션은 문자열을 분리하는 함수를 사용하기 때문에 매우 일반적입니다 (필요한 조건으로 나눌 수 있음). 또한 중간 문자열 / 목록을 만들지 않습니다 ( 결합 을 제거 할 수 있으며 각 그룹이 반복자이므로 표현식이 게으르게됩니다)


4

re 모듈 기능 re.split을 사용하는 대신 팬더의 series.str.split 메소드를 사용하여 동일한 결과를 얻을 수 있습니다.

먼저 위의 문자열로 시리즈를 만든 다음 해당 메소드를 시리즈에 적용하십시오.

thestring = pd.Series("Hey, you - what are you doing here!?") thestring.str.split(pat = ',|-')

pat 매개 변수 는 구분 기호를 사용하여 분할 문자열을 배열로 반환합니다. 여기에 두 분리 문자는 | (또는 운영자). 출력은 다음과 같습니다.

[Hey, you , what are you doing here!?]


1
그것은 장황한 문제가 아니라 문자열을 팬더 시리즈로 변환 한 후 간단한 작업을 수행하기 위해 전체 라이브러리 (BTW)를 가져 오는 사실입니다. "Occam friendly"는 아닙니다.
— zar3bski

3

나는 파이썬을 다시 알고 있고 똑같은 것이 필요했습니다. findall 솔루션이 더 나을 수도 있지만, 나는 이것을 생각해 냈습니다.

tokens = [x.strip() for x in data.split(',')]

영리하고 공백이없는 엠-대시를 제외하고 생각할 수있는 모든 영어 문법 구조에서 작동해야합니다. (해결 방법)
— ninjagecko 2016 년

3

maketrans와 번역을 사용하면 쉽고 깔끔하게 할 수 있습니다

import string
specials = ',.!?:;"()<>[]#$=-/'
trans = string.maketrans(specials, ' '*len(specials))
body = body.translate(trans)
words = body.strip().split()

Python> = 3.6에
— revliscano

3

Python 3에서는 PY4E-Python for Everybody 의 메소드를 사용할 수 있습니다 .

우리는 문자열 방법을 사용하여 이러한 문제를 모두 해결할 수있는 lower, punctuation하고 translate. 는 translate방법 중 가장 미묘하다. 다음에 대한 설명서가 있습니다 translate.

your_string.translate(your_string.maketrans(fromstr, tostr, deletestr))

에있는 문자를 fromstr같은 위치의 문자로 tostr바꾸고에있는 모든 문자를 삭제하십시오 deletestr. fromstr및 tostr빈 문자열이 될 수 있으며, deletestr매개 변수를 생략 할 수 있습니다.

"문장"을 볼 수 있습니다.

In [10]: import string

In [11]: string.punctuation
Out[11]: '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'  

예를 들어 :

In [12]: your_str = "Hey, you - what are you doing here!?"

In [13]: line = your_str.translate(your_str.maketrans('', '', string.punctuation))

In [14]: line = line.lower()

In [15]: words = line.split()

In [16]: print(words)
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

자세한 내용은 다음을 참조하십시오.


2
문자열의 translate () 및 maketrans () 메소드는 흥미롭지 만이 메소드는 "구분 기호"(또는 공백)에서 분리되지 않습니다. 예상되는 "동굴"과 "에서"…
— Eric O Lebigot

@EricLebigot가 언급 한 것과 같습니다. 위의 방법은 질문이 잘하는 것을하지 않습니다.
— Jeremy Anifacc

2

이를 달성하는 또 다른 방법은 Natural Language Tool Kit ( nltk ) 를 사용하는 것 입니다.

import nltk
data= "Hey, you - what are you doing here!?"
word_tokens = nltk.tokenize.regexp_tokenize(data, r'\w+')
print word_tokens

인쇄합니다 : ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

이 방법의 가장 큰 단점은 nltk 패키지 를 설치 해야한다는 것 입니다.

토큰을 받으면 나머지 nltk 패키지 로 많은 재미있는 일 을 할 수 있다는 이점이 있습니다 .


1

우선, 분할 함수에서 구두점을 구분 기호로 실제로 사용하려는 의도는 아니라고 생각합니다. 설명에서는 결과 문자열에서 구두점을 간단히 제거하고 싶다고 제안합니다.

나는 이것을 자주 자주 접하게되며 일반적인 솔루션에는 다시 필요하지 않습니다.

리스트 이해력을 갖춘 한 줄짜리 람다 함수 :

(필수 import string) :

split_without_punc = lambda text : [word.strip(string.punctuation) for word in 
    text.split() if word.strip(string.punctuation) != '']

# Call function
split_without_punc("Hey, you -- what are you doing?!")
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']


기능 (전통)

전통적인 함수로서, 이것은 여전히 ​​목록 이해력이있는 두 줄에 불과합니다 import string:

def split_without_punctuation2(text):

    # Split by whitespace
    words = text.split()

    # Strip punctuation from each word
    return [word.strip(ignore) for word in words if word.strip(ignore) != '']

split_without_punctuation2("Hey, you -- what are you doing?!")
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']

또한 자연스럽게 수축과 하이픈이있는 단어는 그대로 둡니다. text.replace("-", " ")분할하기 전에 항상 하이픈을 공백으로 바꾸는 데 사용할 수 있습니다 .

Lambda 또는 목록 이해가없는 일반 기능

더 일반적인 해결책 (제거 할 문자를 지정할 수있는 곳)과 목록 이해가 없으면 다음과 같은 이점이 있습니다.

def split_without(text: str, ignore: str) -> list:

    # Split by whitespace
    split_string = text.split()

    # Strip any characters in the ignore string, and ignore empty strings
    words = []
    for word in split_string:
        word = word.strip(ignore)
        if word != '':
            words.append(word)

    return words

# Situation-specific call to general function
import string
final_text = split_without("Hey, you - what are you doing?!", string.punctuation)
# returns ['Hey', 'you', 'what', 'are', 'you', 'doing']

물론 람다 함수를 항상 지정된 문자열로 일반화 할 수 있습니다.


1

우선, 정규 작업보다 빠르게 작동하므로 루프에서 RegEx 작업을 수행하기 전에 항상 re.compile ()을 사용하십시오.

따라서 문제의 경우 먼저 패턴을 컴파일 한 다음 조치를 수행하십시오.

import re
DATA = "Hey, you - what are you doing here!?"
reg_tok = re.compile("[\w']+")
print reg_tok.findall(DATA)

1

여기에 몇 가지 설명이 있습니다.

st = "Hey, you - what are you doing here!?"

# replace all the non alpha-numeric with space and then join.
new_string = ''.join([x.replace(x, ' ') if not x.isalnum() else x for x in st])
# output of new_string
'Hey  you  what are you doing here  '

# str.split() will remove all the empty string if separator is not provided
new_list = new_string.split()

# output of new_list
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

# we can join it to get a complete string without any non alpha-numeric character
' '.join(new_list)
# output
'Hey you what are you doing'

또는 한 줄에 다음과 같이 할 수 있습니다.

(''.join([x.replace(x, ' ') if not x.isalnum() else x for x in st])).split()

# output
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']

업데이트 된 답변


1

두 개의 문자열 (분할 소스 문자열과 분리 문자의 분리 목록 문자열)을 입력으로 사용하여 분리 단어 목록을 출력하는 함수를 작성하십시오.

def split_string(source, splitlist):
    output = []  # output list of cleaned words
    atsplit = True
    for char in source:
        if char in splitlist:
            atsplit = True
        else:
            if atsplit:
                output.append(char)  # append new word after split
                atsplit = False
            else: 
                output[-1] = output[-1] + char  # continue copying characters until next split
    return output

1

분리 문자가 단일 문자라고 가정하지 않고 정규 표현식을 사용하려고 시도하지 않기 때문에 pprzemek의 솔루션을 좋아합니다.

명확성을 위해 위의 솔루션을 더 잘 읽을 수있는 버전은 다음과 같습니다.

def split_string_on_multiple_separators(input_string, separators):
    buffer = [input_string]
    for sep in separators:
        strings = buffer
        buffer = []  # reset the buffer
        for s in strings:
            buffer = buffer + s.split(sep)

    return buffer

0

@ooboo와 같은 문제가 있으며 @ ghostdog74이 주제를 찾았습니다. 아마도 누군가가 내 솔루션을 유용하게 생각합니다.

str1='adj:sg:nom:m1.m2.m3:pos'
splitat=':.'
''.join([ s if s not in splitat else ' ' for s in str1]).split()

공백으로 분할하지 않으려면 공간에 무언가를 입력하고 동일한 문자를 사용하여 분할하십시오.


단어를 사용하여 분할해야하는 경우 어떻게합니까?
— 하르샤 비야 니

0

여기에 여러 개의 deliminater가있는 분할이 있습니다.

def msplit( str, delims ):
  w = ''
  for z in str:
    if z not in delims:
        w += z
    else:
        if len(w) > 0 :
            yield w
        w = ''
  if len(w) > 0 :
    yield w

0

다음은 귀하의 요구에 가장 적합한 답변이라고 생각합니다.

\W+ 이 경우에는 적합하지만 다른 경우에는 적합하지 않을 수 있습니다.

filter(None, re.compile('[ |,|\-|!|?]').split( "Hey, you - what are you doing here!?")

동의 \w하며 \W솔루션은 질문의 제목이 아닙니다. 답에서 |제거해야합니다 ( expr0|expr1대신 생각하고 있음 [char0 char1…]). 또한 compile()정규 표현식이 필요하지 않습니다 .
— Eric O Lebigot

0

여기에 내 걸릴 ....

def split_string(source,splitlist):
    splits = frozenset(splitlist)
    l = []
    s1 = ""
    for c in source:
        if c in splits:
            if s1:
                l.append(s1)
                s1 = ""
        else:
            print s1
            s1 = s1 + c
    if s1:
        l.append(s1)
    return l

>>>out = split_string("First Name,Last Name,Street Address,City,State,Zip Code",",")
>>>print out
>>>['First Name', 'Last Name', 'Street Address', 'City', 'State', 'Zip Code']

0

나는 replace()가장 좋은 길을 좋아한다 . 다음 절차는 문자열 splitlist에 정의 된 모든 구분 기호 를 첫 번째 구분 기호로 변경 splitlist한 다음 해당 구분 기호로 텍스트를 분할합니다. 또한 splitlist빈 문자열 인 경우도 설명 합니다. 빈 문자열이없는 단어 목록을 반환합니다.

def split_string(text, splitlist):
    for sep in splitlist:
        text = text.replace(sep, splitlist[0])
    return filter(None, text.split(splitlist[0])) if splitlist else [text]

0
def get_words(s):
    l = []
    w = ''
    for c in s.lower():
        if c in '-!?,. ':
            if w != '': 
                l.append(w)
            w = ''
        else:
            w = w + c
    if w != '': 
        l.append(w)
    return l

사용법은 다음과 같습니다.

>>> s = "Hey, you - what are you doing here!?"
>>> print get_words(s)
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']

0

가역 연산을 원할 경우 (구분 기호 유지)이 기능을 사용할 수 있습니다.

def tokenizeSentence_Reversible(sentence):
    setOfDelimiters = ['.', ' ', ',', '*', ';', '!']
    listOfTokens = [sentence]

    for delimiter in setOfDelimiters:
        newListOfTokens = []
        for ind, token in enumerate(listOfTokens):
            ll = [([delimiter, w] if ind > 0 else [w]) for ind, w in enumerate(token.split(delimiter))]
            listOfTokens = [item for sublist in ll for item in sublist] # flattens.
            listOfTokens = filter(None, listOfTokens) # Removes empty tokens: ''
            newListOfTokens.extend(listOfTokens)

        listOfTokens = newListOfTokens

    return listOfTokens

0

최근 에이 작업을 수행해야했지만 표준 라이브러리 str.split함수 와 다소 일치하는 함수를 원했습니다 .이 함수는 0 또는 1 개의 인수로 호출 될 때 표준 라이브러리와 동일하게 작동합니다.

def split_many(string, *separators):
    if len(separators) == 0:
        return string.split()
    if len(separators) > 1:
        table = {
            ord(separator): ord(separator[0])
            for separator in separators
        }
        string = string.translate(table)
    return string.split(separators[0])

참고 :이 기능은 구분 기호가 단일 문자로 구성되어있을 때만 유용합니다 (사용 사례와 동일).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.