Seite 1 von 2
String trennen
Verfasst: Montag 30. Januar 2017, 08:10
von Kreser06
Hallo, komme nicht mehr weiter.
wie kann man ein String mit Zahl und Text zusammengeschrieben, trennen?
Habe schon mit Regulären Ausdrücken versucht, aber das Problem ist, das ich um die 1000 Zeilen habe. In den Zeilen stehen verschiedene Formen des Strings drin.
Es gibt Zeilen nur mit Text (Abcd) , Text und Zahl (Abcd123 / 123Abcd / Abcd123Abcd), mit Zahl und Sonderzeichen (1 +1 / 2*2) aber auch Zahl Buchstabe Zahl (2x2).
ich möchte alle zahlen und Text trennen, so dass ein Leerzeichen dazwischen ist. Aber Zahlen mit einem Buchstaben oder Sonderzeichen dazwischen soll so bleiben.
Beispiel:
- 123Abcd ---> 123 Abcd
Abcd123---> Abcd 123
Abcd123Abcd--->Abcd 123 Abcd
1+1--->1+1
2x2--->2x2
2x2Abcd--->2x2 Abcd usw.
Und dann habe ich noch zusammengeschriebene Wörter die mit Großbuchstaben anfangen, die müssen auch getrennt werden.
Beispiel :
- DasIstEinText---> Das Ist Ein Text.
wie kann man das am einfachsten realisieren?
Danke im Voraus.
Re: String trennen
Verfasst: Montag 30. Januar 2017, 08:26
von noisefloor
Hallo,
wie kann man das am einfachsten realisieren?
"Einfach" ist ja relativ
Ich würde es erstmal wahrscheinlich so angehen, dass ich eine Satz Regeln zum Einfügen eines Leerzeichens definieren würde, wobei immer das aktuelle Zeichen und das vorhergehende betrachtet wird.
Dann würde ich zeichenweise über den String iterieren und dabei den neuen String inkl. Leerzeichen bauen.
So kriegt man das auf jeden Fall hin - was nicht heißt, dass es nicht eine elegantere Lösung gibt
Gruß, noisefloor
Re: String trennen
Verfasst: Montag 30. Januar 2017, 08:30
von Kreser06
ja daran habe ich auch schon gedacht, dachte nur dass jemand was besseres kennt.
dann versuche ich es mal.
Re: String trennen
Verfasst: Montag 30. Januar 2017, 13:51
von pillmuncher
Mal so als erster Versuch:
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf-8
import re
def main():
lines = [
'123Abcd',
'Abcd123',
'Abcd123Abcd',
'1+1',
'2x2',
'2x2Abcd',
'DasIstEinText',
'123xyz'
]
expected = [
'123 Abcd',
'Abcd 123',
'Abcd 123 Abcd',
'1+1',
'2x2',
'2x2 Abcd',
'Das Ist Ein Text',
'123 xyz'
]
pattern = '\d+(?:[x+](?![A-Za-z]))?\d*|[A-Z][a-z]*|[a-z]+'
result = [' '.join(re.findall(pattern, line)) for line in lines]
print result
assert result == expected
if __name__ == '__main__':
main()
Ergebnis:
Code: Alles auswählen
['123 Abcd', 'Abcd 123', 'Abcd 123 Abcd', '1+1', '2x2', '2x2 Abcd', 'Das Ist Ein Text', '123 xyz']
Re: String trennen
Verfasst: Montag 30. Januar 2017, 15:33
von snafu
Unter der Annahme, dass die mathematischen Ausdrücke nicht komplexer werden als gezeigt (erkennt dabei "+", "-", "x" bzw "*" sowie ":" bzw "/"):
Code: Alles auswählen
from __future__ import print_function
import re
PATTERNS = {
'word': r'[A-Z][a-z]*',
'digits': r'\d+',
'formula': r'\d+[+-:x/*]\d+',
}
def split(patterns, lines):
if isinstance(patterns, dict):
patterns = patterns.values()
pattern = re.compile('|'.join(patterns))
for line in lines:
yield pattern.findall(line)
def main():
lines = [
'123Abcd',
'Abcd123',
'Abcd123Abcd',
'1+23',
'34x5TextBeispiel',
'30*13',
'4000/4Murx',
'5453:45BlaBla4534-25',
'235x256Abcd',
'DasIstEin123*456Text',
]
for parts in split(PATTERNS, lines):
print(*parts)
if __name__ == '__main__':
main()
Re: String trennen
Verfasst: Samstag 4. Februar 2017, 16:29
von Kreser06
hallo, sorry dass ich erst jetzt antworte, hatte keine Zeit.
Ich beides ausprobiert und es funktioniert wunderbar. Allerdings ist meine Liste etwas komplexer.
Liste.txt
http://pastebin.com/LssMP088
Hier der angepasste Code:
Code: Alles auswählen
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import print_function
import io
import re
PATTERNS = [
r'\+\d', # +2, +7
r'\d[+x]\d', # 1+1, 2x2
r'(?<=\b)[A-ZА-Я]{1,2}\d{1,2}\b', # A1, AB12
r'\b[JT][ui][CJ][ei]', # JuCe TV, TiJi
r'[A-ZА-Я][a-zа-я]+\.?', # Abzde, int.
r'[A-Za-zА-Яа-я][A-ZА-Яa-zа-я]+\.?',# ABSDE, Int.
r'(?<=\b)[A-ZА-Я]{1,2}(?=\b)', # A, AB, ABC
r'\d[A-ZА-Я]\b', # 1A
r'\d\.?\d+', # 1234, 2.0, 3.123
r'\d',
]
def split(patterns, datei):
if isinstance(patterns, dict):
patterns = patterns.values()
pattern = re.compile('|'.join(patterns))
for line in datei:
line = re.sub('[\[\(][^\(\)\[\]]*[\]\)]', '', line) # Klammer und deren Inhalt entfernen
line = re.sub('(?<!(INT))(?<!(int))[_.-](?!\d)', ' ', line) # Unnötige Sonderzeichen entfernen
line = line.rstrip()
yield pattern.findall(line)
def main():
filename_liste = 'Liste.txt'
with io.open(filename_liste, 'r', encoding='utf-8-sig') as datei:
for parts in split(PATTERNS, datei):
for teil in range(len(parts)):
if len(parts[teil]) <= 3:
if parts[teil] == 'Geo' or parts[teil] == 'GEO' or parts[teil] == 'geo'\
or parts[teil] == 'Nat' or parts[teil] == 'NAT' or parts[teil] == 'nat'\
or parts[teil] == 'Дом' or parts[teil] == 'ДОМ' or parts[teil] == 'дом'\
or parts[teil] == 'Моя' or parts[teil] == 'МОЯ' or parts[teil] == 'моя'\
or parts[teil] == 'Кто' or parts[teil] == 'КТО' or parts[teil] == 'кто':
parts[teil] = parts[teil].title()
else:
parts[teil] = parts[teil].upper()
else:
if parts[teil] != 'JuCe' and parts[teil] != 'TiJi':
parts[teil] = parts[teil].title()
print(*parts)
if __name__ == '__main__':
main()
Wie man sieht sind es die Sendernamen der IPTV-Sender, die ich sortieren möchte. Es gibt alle möglichen Sender, hauptsächlich aber die russischen. Siehe Liste.txt.
Das funktioniert alles soweit ganz gut, aber es kann bestimmt eleganter gelöst werden?
Code:
Code: Alles auswählen
for teil in range(len(parts)):
if len(parts[teil]) <= 3:
if parts[teil] == 'Geo' or parts[teil] == 'GEO' or parts[teil] == 'geo'\
or parts[teil] == 'Nat' or parts[teil] == 'NAT' or parts[teil] == 'nat'\
or parts[teil] == 'Дом' or parts[teil] == 'ДОМ' or parts[teil] == 'дом'\
or parts[teil] == 'Моя' or parts[teil] == 'МОЯ' or parts[teil] == 'моя'\
or parts[teil] == 'Кто' or parts[teil] == 'КТО' or parts[teil] == 'кто':
parts[teil] = parts[teil].title()
else:
parts[teil] = parts[teil].upper()
else:
if parts[teil] != 'JuCe' and parts[teil] != 'TiJi':
parts[teil] = parts[teil].title()
Wie kann ich den Code mit RegEx umschreiben? Da es noch mehr Ausnahmen kommen könnten, ist es evtl. besser mit RegEx zu schreiben. Aber leider ist mein Python-Kenntnis nicht ganz so groß.
Hoffe ihr könnt mir helfen.
Re: String trennen
Verfasst: Samstag 4. Februar 2017, 17:33
von Sirius3
@Kreser06: statt den Inhalt einer Liste zu ändern, erzeugt man am besten eine neue Liste. Für Dein Problem böte es sich an, die verschiedenen Ausnahmen in Sets zu speichern:
Code: Alles auswählen
SHORT_NAMES_TO_TITLE = {'geo', 'nat', 'дом', 'моя', 'кто'}
LONG_NAMES_TO_IGNORE = {'JuCe', 'TiJi'}
[...]
renamed_parts = []
for part in parts:
if len(part) <= 3:
if part.lower() in SHORT_NAMES_TO_TITLE:
renamed_parts.append(part.title())
else:
renamed_parts.append(part.upper())
elif part in LONG_NAMES_TO_IGNORE:
renamed_parts.append(part)
else:
renamed_parts.append(part.title())
print(*renamed_parts)
Re: String trennen
Verfasst: Samstag 4. Februar 2017, 17:41
von Kreser06
Cool, vielen Dank. Das sieht sehr übersichtlich aus.
Aber was soll das bedeuten?
Ist das ein Platzhalter für den anderen Code?
Re: String trennen
Verfasst: Samstag 4. Februar 2017, 19:40
von snafu
Kreser06 hat geschrieben:
Falls es eine allgemeine Regex zum Matchen von Floats sein darf:
Re: String trennen
Verfasst: Sonntag 5. Februar 2017, 17:09
von Kreser06
hallo noch mal,
komme wieder mal nicht weiter.
Mit euerer Hilfe habe ich nun jetzt einen funktionierenden Code.
http://pastebin.com/UqAFm4kP
Nun wollte ich es weiterverarbeiten und als Modul benutzen. Habe mir zwei Dateien erstellt:
- main.py - Hauptcode. http://pastebin.com/QcZpPEYy
- playlist2userbouquet.py - da werden/sollten die verschiedenen Aufgaben erledigt. http://pastebin.com/Jc5R59re
Statt
datei.txt habe ich vorher eine Dictionary erstellt mit Namen und dazugehörenden Links (
m3u_to_m3u_dict). Diese Dictionary bzw. die Namen wollte ich mit dem Code von oben anpassen.
Jetzt wollte ich aus der main.py auf den Code zugreifen, aber leider funktioniert das irgendwie nicht. Habe schon alles mögliche(was mein Python-Wissen zulässt) ausprobiert. Ich bekomme den Fehler:
[codebox=pycon file=Unbenannt.txt]Traceback (most recent call last):
File "/Users/elenakretschmann/Documents/=PYTHON=/Playlist/BBEditRunTemp-main.py", line 34, in <module>
main()
File "/Users/elenakretschmann/Documents/=PYTHON=/Playlist/BBEditRunTemp-main.py", line 31, in main
m3u_dict_anpassen()
File "/Users/elenakretschmann/Documents/=PYTHON=/Playlist/BBEditRunTemp-main.py", line 25, in m3u_dict_anpassen
for parts in anpassen.split(anpassen.PATTERNS, liste):
TypeError: split() takes 2 positional arguments but 3 were given[/code]
Wie man sieht habe ich aus Dictionary die Namen extrahiert, da ich dachte dass es evtl. daran liegt.
Code: Alles auswählen
liste = []
for key in playlist.m3u_dict.keys():
liste.append(key)
Eigentlich wollte ich direkt mit der Dict. weiter machen und wenn der Code(Anpassen) fertig ist, wollte ich die Dict. sozusagen aktualisieren mit den den richtigen/angepassten Namen und dazu gehörenden Links. Und später weiter machen.
Was mache ich falsch?
Danke schon mal für eure Mühe.
Re: String trennen
Verfasst: Sonntag 5. Februar 2017, 17:39
von __deets__
Du hast eine Methode split geschrieben, der fehlt aber das obligatorische self-Argument als erstes.
Nachtrag: das gilt auch fuer deine andere Methode, gross_klein_schreibung.
Re: String trennen
Verfasst: Sonntag 5. Februar 2017, 17:47
von Kreser06
ohh man, Danke.
Re: String trennen
Verfasst: Sonntag 5. Februar 2017, 20:01
von snafu
Hier noch ein Verbesserungvorschlag, um den Code etwas pythonischer zu gestalten:
Code: Alles auswählen
def m3u_to_m3u_dict(self, filename_m3u):
try:
with io.open(filename_m3u, 'r', encoding='utf-8-sig') as m3u:
for zeile in m3u:
if zeile.startswith('#EXTINF'):
if zeile[11] != '=' and not zeile.startswith('='):
name = zeile.rstrip().replace('#EXTINF:-1,','')
link = m3u.readline().rstrip()
self.m3u_dict[name] = link
except IOError as error:
print('Fehler beim Öffnen:', error)
Ich verwende hier startswith() und habe bei name und link mehrere Methoden hintereinander geschaltet. Außerdem fange ich den etwas aussagekräftigeren IOError ab. Die Fehlermeldung wurde angepasst, da auch andere Fehlerarten, wie z.B. verweigerter Lesezugriff auftreten können. Wenn man trotzdem eine eigene Meldung bei einer nicht existierenden Datei haben möchte:
Code: Alles auswählen
try:
# ...
except FileNotFoundError:
msg = 'Die Datei {!r} existiert nicht!'
print(msg.format(filename_m3u))
except IOError as error:
print('Fehler beim Öffnen:', error)
Re: String trennen
Verfasst: Sonntag 5. Februar 2017, 20:04
von Kreser06
Cool, Danke.
Re: String trennen
Verfasst: Donnerstag 9. Februar 2017, 19:18
von Kreser06
Hallo allerseits,
habe ein nächstes Problem und zwar möchte den Code etwas ändern, aber leider funktioniert das nicht so wie ich es erwartet hatte.
Hier habe ich die Dictionary (name) an SPLIT weitergegeben:
Code: Alles auswählen
def NAME_DICT_ANPASSEN():
name = playlist.m3u_name_dict
for parts in anpassen.SPLIT(name):
print ('xxxxxxxxxxxxx')
anpassen.GROSS_KLEIN_SCHREIBUNG(parts)
und hier wird es verarbeitet. (
for line in name.values():)
Code: Alles auswählen
def SPLIT(self, name):
playlist = PLAYLIST()
patterns = self.PATTERNS
if isinstance(patterns, dict):
patterns = patterns.values()
pattern = re.compile('|'.join(patterns))
for line in name.values():
print ('XXXXX ' + line)
line = re.sub('[\[\(][^\(\)\[\]]*[\]\)]', '', line) # Klammer und deren Inhalt entfernen
line = re.sub('(?<!(INT))(?<!(int))[_.-](?!\d)', ' ', line) # Unnötige Sonderzeichen entfernen
line = line.rstrip()
yield pattern.findall(line)
Allerdings muss ich jetzt nicht die komplette Dict. weitergeben, sondern jeweils den Wert davon z.B. :
Code: Alles auswählen
for name in playlist.m3u_name_dict.values():
print ('v: ' + name)
anpassen.SPLIT(name)
aber leider passiert mit dem code (SPLIT) nichts. Warum?
hier nochmal Beides:
Code: Alles auswählen
def NAME_DICT_ANPASSEN():
for name in playlist.m3u_name_dict.values():
print ('v: ' + name)
anpassen.SPLIT(name)
und:
Code: Alles auswählen
def SPLIT(self, name):
playlist = PLAYLIST()
patterns = self.PATTERNS
if isinstance(patterns, dict):
patterns = patterns.values()
pattern = re.compile('|'.join(patterns))
for line in name:
print ('XXXXX ' + line)
line = re.sub('[\[\(][^\(\)\[\]]*[\]\)]', '', line) # Klammer und deren Inhalt entfernen
line = re.sub('(?<!(INT))(?<!(int))[_.-](?!\d)', ' ', line) # Unnötige Sonderzeichen entfernen
line = line.rstrip()
yield pattern.findall(line)
im zweitem Beispiel wird nur
print ('v: ' + name) ausgegeben.
Habe ich was übersehen?
Re: String trennen
Verfasst: Donnerstag 9. Februar 2017, 19:30
von Sirius3
@Kreser06: Du solltest dringend Deine Variablenschreibweise an die üblichen Konventionen anpassen; der Code ist deshalb nur schwer lesbar. Warum nichts ausgegeben wird? Du solltest nochmal nachlesen, wie ein Generator funktioniert.
Re: String trennen
Verfasst: Freitag 10. Februar 2017, 20:24
von Kreser06
@Sirius3:
Hallo, die Variablenschreibweise werde ich natürlich anpassen, weil ich noch am testen bin ist es etwas lästig alles zu ändern, aber danke für den Tipp.
Und jetzt zu der
yield-Anweisung. In meinem Fall werden ja alle Übereinstimmungen im Text gesucht und nacheinander ausgegeben.
Code: Alles auswählen
for value in name.values():
value = re.sub('[\[\(][^\(\)\[\]]*[\]\)]', '', value) # Klammer und deren Inhalt entfernen
value = re.sub('(?<!(INT))(?<!(int))[_.-](?!\d)', ' ', value) # Unnötige Sonderzeichen entfernen
value = value.strip()
yield pattern.findall(value)
Hier wird ja die Dictionary übergeben und mit
for value in name.values(): der Wert ausgelesen z.B. '
Text 123 TEXTText1'. Danach im
yield pattern.findall(value) werden die passenden RegEx Übereinstimmungen gesucht und alle an
yield übergeben. Habe ich das richtig verstanden?
Und wenn ich vom Anfang an nicht die Dict., sondern Direkt den string value z.B. '
Text 123 TEXTText1' an yield weitergebe dann passiert nichts.
Kannst du/ihr mir bitte auf die Sprünge Helfen? Ich komme wirklich nicht weiter. Bin halt Anfänger. :K
Re: String trennen
Verfasst: Freitag 10. Februar 2017, 21:13
von Sirius3
@Kreser06: es geht nicht darum, was der Generator macht, sondern wie Du ihn benutzt/aufrufst.
Re: String trennen
Verfasst: Freitag 10. Februar 2017, 21:52
von Kreser06
ich hab's.
Code: Alles auswählen
for value in playlist.m3u_name_dict.values():
print (value)
gen = anpassen.SPLIT(value)
test = next(gen)
print (test)
Danke das du es so spanned gemacht hast
. Aber jetzt verstehe ich das auch. Danke
Re: String trennen
Verfasst: Freitag 10. Februar 2017, 22:37
von BlackJack
@Kreser06: Das sieht nicht wirklich sinnvoll aus‽