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


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. fromstrtostr빈 문자열이 될 수 있으며, 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.