2016-09-25 2 views
5

Ich möchte eine Zeichenfolge auf jede Kombination von Delimitern, die ich zur Verfügung stelle, aufteilen. Zum Beispiel, wenn die Zeichenfolge:Wie wird eine Zeichenkette auf mehrere Trennzeichen aufgeteilt, aber nur einige?

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

Und die Trennzeichen sind \., , und \s. Ich möchte jedoch alle Trennzeichen außer Whitespace \s erfassen. Die Ausgabe sollte sein:

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

Meine Lösung so weit ist, wird mit dem re Modul:

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

Dies ist jedoch fängt Leerzeichen als auch. Ich habe versucht, andere Muster wie [(\.)(,)\s]+ zu verwenden, aber sie funktionieren nicht.

Bearbeiten: @PadraicCunningham machte eine kluge Beobachtung. Für Delimiter wie Some text ,. , some more text, ich möchte nur führende und nachfolgende Leerzeichen aus ,. , und nicht Whitespace innerhalb entfernen.

+0

Könnten Sie das Entfernen ' \ 's zunächst? – eavidan

+0

Was ist mit dem Entfernen der Leerzeichen aus Strings, die sich aus dem aufgenommenen Ergebnis ergeben? Dies ist keine verallgemeinerte Lösung des Problems und sollte aufgrund der Einfachheit der Regex "funktionieren". – user2864740

+0

@eavidan Aber dann teilt es sich nicht auf Whitespace. Auf diese Weise müsste ich 're.split ('\ s', ...)' auf jedem Element der zurückgegebenen Liste ab dem ersten Split ausführen. – hazrmard

Antwort

5

Die folgende Vorgehensweise die einfachste sein würde, nehme ich an ...

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

Der Ausgang:

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

'wenn i.strip()' ist ausreichend, um nach einem leeren String zu suchen –

+0

@PadraicCunningham, genau, denn nach dem Splitten haben wir sie im Ergebnis: '... ',', 'some', '', sense ',' ''. Einzelne Leerzeichen und nachfolgende Leerzeichen sollten herausgefiltert werden. – RomanPerekhrest

+0

'strip()' entfernt keine Leerzeichen zwischen anderen Begrenzern. Ich denke, Sie müssen sie explizit entfernen durch etwas wie '[i für i in [re (r' \ s ',' ', i) für i in re.split (r' ([,. \ S] +) ', s)] if len (i)> 0] ' –

0

aktualisieren basierend auf zuletzt der OP

Python 3 . *:

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

Ausgang:

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

Ich glaube, dies die effizienteste Option in Bezug auf Speicher ist, und wirklich effizient in Bezug auf Rechenzeit:

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

'' This, denke ich., ???? MACHT, irgendwie sinnvoll "" und es bricht, überprüfe die OP's Bearbeitung. –

+0

Ich wusste nicht, dass Sie Gruppen in 're.split()' erfassen können. Gut zu wissen. – Bharel

+0

@PadraicCunningham Es wurde behoben. Btw, es ist immer noch effizienter in Bezug auf Speicher, da es 1/3 der akzeptierten Lösung benötigt. – Bharel

3

HINWEIS: Nach dem neuen bearbeiten auf der Frage, Ich habe meine alte Regex verbessert. Der neue ist ziemlich lang aber vertrau mir, es ist Arbeit!

schlage ich ein Muster unten als Trennzeichen der Funktion re.split():

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

Meine Abhilfe hier erfordert keine pre/post Raum Modifikation. Die Sache, die Regex-Arbeit macht, ist, wie Sie die Regex-Ausdrücke mit or bestellen. Meine kursorische Strategie ist jedes Muster, das mit einem Leerzeichen behandelt wird.

Siehe DEMO

Zusätzliche

Nach Kommentar des @ revo er bot eine andere shorten Version von meiner, die

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

See ist DEMO

+0

Ersetzt immer noch 'Text,. , einige. Siehe Bearbeiten von OP. – Bharel

+0

@Bharel bitte überprüfen Sie es. – fronthem

+1

@hazrmard eine andere Problemumgehung. – fronthem

Verwandte Themen