2016-09-25 15 views
5

Chcę podzielić ciąg na dowolną kombinację dostarczonych ograniczników. Na przykład, jeśli ciąg jest:Jak podzielić łańcuch na wiele ograniczników, ale przechwytuje tylko niektóre?

s = 'This, I think,., کباب MAKES , some sense ' 

I separatory są \., , i \s. Jednak chcę przechwycić wszystkie ograniczniki z wyjątkiem spacji \s. Wyjście powinno być:

['This', ',', 'I', 'think', ',.,', 'کباب', 'MAKES', ',', 'some', 'sense'] 

Moje rozwiązanie do tej pory jest za pomocą modułu re:

pattern = '([\.,\s]+)' 
re.split(pattern, s) 

Jednak ten rejestruje odstępy, jak również. Próbowałem używać innych wzorców, takich jak [(\.)(,)\s]+, ale one nie działają.

Edytuj: @PadraicCunningham dokonał wnikliwej obserwacji. W przypadku ograniczników takich jak Some text ,. , some more text, chciałbym tylko usunąć początkowe i końcowe spacje z ,. ,, a nie białe spacje wewnątrz.

+0

można po prostu usunąć ' \ s' początkowo? – eavidan

+0

Co powiesz na usunięcie białych znaków z ciągów wynikowych z przechwyconego wyniku? Nie jest to uogólnione rozwiązanie problemu i powinno "działać" tutaj ze względu na prosty charakter regex. – user2864740

+0

@eavidan Ale wtedy nie dzieli się na białe znaki. W ten sposób musiałbym uruchomić 're.split ('\ s', ...)' na każdym elemencie zwróconej listy z pierwszego podziału. – hazrmard

Odpowiedz

5

następujące podejście byłoby najbardziej prosty, przypuszczam ...

s = 'This, I think,., کباب MAKES , some sense ' 
pattern = '([\.,\s]+)' 
splitted = [i.strip() for i in re.split(pattern, s) if i.strip()] 

Wyjście:

['This', ',', 'I', 'think', ',.,', 'کباب', 'MAKES', ',', 'some', 'sense'] 
+1

'if i.strip()' wystarcza, aby sprawdzić pusty ciąg –

+0

@PadraicCunningham, dokładnie, ponieważ po podzieleniu mamy je w wyniku: '... ',', 'niektóre', '', ' "," ". Pojedyncze spacje i spacje końcowe powinny być odfiltrowane. – RomanPerekhrest

+0

'strip()' nie usunie białych znaków osadzonych między innymi ogranicznikami. Domyślam się, że musisz usunąć je jawnie przez coś takiego jak '[i for i in [re.sub (r '\ s', '', i) dla i in re.split (r '([,. \ S] +) ', s)] jeśli len (i)> 0] ' –

0

Aktualizacja oparta na ostatniej edycji OP

Python 3 . *:

list(filter(None, re.split('([.,]+(?:\s+[.,]+)*)|\s', s))) 

wyjściowa:

['This', ',', 'I', 'think', ',.,', 'کباب', 'MAKES', ',', 'some', 'sense'] 
0

Wierzę, że to jest najbardziej wydajnym rozwiązaniem dotyczących pamięci i bardzo efektywny czas dotyczące obliczeń:

import re 
from itertools import chain 
from operator import methodcaller 

input_str = 'This, I think,., ???? MAKES , some sense ' 

iterator = filter(None, # Filter out all 'None's 
        chain.from_iterable( # Flatten the tuples into one long iterable 
        map(methodcaller("groups"), # Take the groups from each match. 
         re.finditer("(.*?)(?:([\.,]+)|\s+|$)", input_str)))) 

# If you want a list: 
list(iterator) 
+0

' 'To, myślę,., ???? MAKES, jakiś sens "i się psuje, sprawdź edycję OP. –

+0

Nie wiedziałem, że możesz przechwytywać grupy w 're.split()'. Dobrze wiedzieć. – Bharel

+0

@PadraicCunningham Naprawiono. Przy okazji, jest jeszcze bardziej wydajny w odniesieniu do pamięci, ponieważ zajmuje 1/3 akceptowanego rozwiązania. – Bharel

3

UWAGA: Według nowej edycji na pytanie, Poprawiłem moje stare wyrażenie regularne. Ten nowy jest dość długi, ale uwierz mi, to działa!

Proponuję wzór poniżej jako ogranicznik funkcji re.split():

(?<![,\.\ ])(?=[,\.]+)|(?<=[,\.])(?![,\.\ ])|(?<=[,\.])\ +(?![,\.\ ])|(?<![,\.\ ])\ +(?=[,\.][,\.\ ]+)|(?<![,\.\ ])\ +(?![,\.\ ]) 

Moja obejście tutaj nie wymaga żadnych pre/post modyfikację przestrzeni. Rzeczą, która sprawia, że ​​wyrażenie regularne działa, jest to, w jaki sposób zamawiamy wyrażenie regex z or. Moja pobieżna strategia to wszelkie wzorce, które zajmują się wiodącą przestrzenią, będą oceniane jako ostatnie.

Zobacz DEMO

dodatkowe

Według komentarza @ Revo on przedstawił wersję inny skrócić kopalni, która jest

\s+(?=[^.,\s])|\b(?:\s+|(?=[,.]))|(?<=[,.])\b 

Zobacz DEMO

+0

Wciąż zastępuje 'Jakiś tekst,. , niektóre ". Zobacz edycję OP. – Bharel

+0

@Bharel proszę to sprawdzić. – fronthem

+1

@hazrmard innego obejścia. – fronthem