String trennen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Kreser06
User
Beiträge: 16
Registriert: Samstag 21. Januar 2017, 11:49

String trennen

Beitragvon Kreser06 » Montag 30. Januar 2017, 08:10

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.
Benutzeravatar
noisefloor
User
Beiträge: 1739
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Re: String trennen

Beitragvon noisefloor » Montag 30. Januar 2017, 08:26

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
Kreser06
User
Beiträge: 16
Registriert: Samstag 21. Januar 2017, 11:49

Re: String trennen

Beitragvon Kreser06 » Montag 30. Januar 2017, 08:30

ja daran habe ich auch schon gedacht, dachte nur dass jemand was besseres kennt.
dann versuche ich es mal.
Benutzeravatar
pillmuncher
User
Beiträge: 1055
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Re: String trennen

Beitragvon pillmuncher » Montag 30. Januar 2017, 13:51

Mal so als erster Versuch:
  1. #!/usr/bin/env python
  2. # coding: utf-8
  3.  
  4. import re
  5.  
  6. def main():
  7.     lines = [
  8.         '123Abcd',
  9.         'Abcd123',
  10.         'Abcd123Abcd',
  11.         '1+1',
  12.         '2x2',
  13.         '2x2Abcd',
  14.         'DasIstEinText',
  15.         '123xyz'
  16.     ]
  17.     expected = [
  18.         '123 Abcd',
  19.         'Abcd 123',
  20.         'Abcd 123 Abcd',
  21.         '1+1',
  22.         '2x2',
  23.         '2x2 Abcd',
  24.         'Das Ist Ein Text',
  25.         '123 xyz'
  26.     ]
  27.     pattern = '\d+(?:[x+](?![A-Za-z]))?\d*|[A-Z][a-z]*|[a-z]+'
  28.     result = [' '.join(re.findall(pattern, line)) for line in lines]
  29.     print result
  30.     assert result == expected
  31.  
  32. if __name__ == '__main__':
  33.     main()
Ergebnis:
  1. ['123 Abcd', 'Abcd 123', 'Abcd 123 Abcd', '1+1', '2x2', '2x2 Abcd', 'Das Ist Ein Text', '123 xyz']
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
snafu
User
Beiträge: 5157
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Re: String trennen

Beitragvon snafu » Montag 30. Januar 2017, 15:33

Unter der Annahme, dass die mathematischen Ausdrücke nicht komplexer werden als gezeigt (erkennt dabei "+", "-", "x" bzw "*" sowie ":" bzw "/"):
  1. from __future__ import print_function
  2. import re
  3.  
  4. PATTERNS = {
  5.     'word': r'[A-Z][a-z]*',
  6.     'digits': r'\d+',
  7.     'formula': r'\d+[+-:x/*]\d+',
  8. }
  9.  
  10. def split(patterns, lines):
  11.     if isinstance(patterns, dict):
  12.         patterns = patterns.values()
  13.     pattern = re.compile('|'.join(patterns))
  14.     for line in lines:
  15.         yield pattern.findall(line)
  16.  
  17. def main():
  18.     lines = [
  19.         '123Abcd',
  20.         'Abcd123',
  21.         'Abcd123Abcd',
  22.         '1+23',
  23.         '34x5TextBeispiel',
  24.         '30*13',
  25.         '4000/4Murx',
  26.         '5453:45BlaBla4534-25',
  27.         '235x256Abcd',
  28.         'DasIstEin123*456Text',
  29.     ]
  30.     for parts in split(PATTERNS, lines):
  31.         print(*parts)
  32.  
  33. if __name__ == '__main__':
  34.     main()
shcol (Repo | Doc | PyPi)
Kreser06
User
Beiträge: 16
Registriert: Samstag 21. Januar 2017, 11:49

Re: String trennen

Beitragvon Kreser06 » Samstag 4. Februar 2017, 16:29

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:
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from __future__ import print_function
  4. import io
  5. import re
  6.  
  7. PATTERNS = [
  8.     r'\+\d',                            # +2, +7
  9.     r'\d[+x]\d',                        # 1+1, 2x2
  10.     r'(?<=\b)[A-ZА-Я]{1,2}\d{1,2}\b',   # A1, AB12
  11.     r'\b[JT][ui][CJ][ei]',              # JuCe TV, TiJi
  12.     r'[A-ZА-Я][a-zа-я]+\.?',            # Abzde, int.
  13.     r'[A-Za-zА-Яа-я][A-ZА-Яa-zа-я]+\.?',# ABSDE, Int.
  14.     r'(?<=\b)[A-ZА-Я]{1,2}(?=\b)',      # A, AB, ABC
  15.     r'\d[A-ZА-Я]\b',                    # 1A
  16.     r'\d\.?\d+',                        # 1234, 2.0, 3.123
  17.     r'\d',
  18. ]
  19.  
  20. def split(patterns, datei):
  21.     if isinstance(patterns, dict):
  22.         patterns = patterns.values()
  23.     pattern = re.compile('|'.join(patterns))
  24.     for line in datei:
  25.         line = re.sub('[\[\(][^\(\)\[\]]*[\]\)]', '', line)         # Klammer und deren Inhalt entfernen
  26.         line = re.sub('(?<!(INT))(?<!(int))[_.-](?!\d)', ' ', line) # Unnötige Sonderzeichen entfernen
  27.         line = line.rstrip()
  28.         yield pattern.findall(line)
  29.        
  30.  
  31. def main():
  32.    
  33.     filename_liste = 'Liste.txt'
  34.     with io.open(filename_liste, 'r', encoding='utf-8-sig') as datei:
  35.         for parts in split(PATTERNS, datei):
  36.            
  37.             for teil in range(len(parts)):
  38.                 if len(parts[teil]) <= 3:
  39.                     if parts[teil] == 'Geo' or parts[teil] == 'GEO' or parts[teil] == 'geo'\
  40.                         or parts[teil] == 'Nat' or parts[teil] == 'NAT' or parts[teil] == 'nat'\
  41.                         or parts[teil] == 'Дом' or parts[teil] == 'ДОМ' or parts[teil] == 'дом'\
  42.                         or parts[teil] == 'Моя' or parts[teil] == 'МОЯ' or parts[teil] == 'моя'\
  43.                         or parts[teil] == 'Кто' or parts[teil] == 'КТО' or parts[teil] == 'кто':
  44.                         parts[teil] = parts[teil].title()
  45.                     else:
  46.                         parts[teil] = parts[teil].upper()
  47.                 else:
  48.                     if parts[teil] != 'JuCe' and parts[teil] != 'TiJi':
  49.                         parts[teil] = parts[teil].title()
  50.  
  51.             print(*parts)
  52. if __name__ == '__main__':
  53.     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:
  1.             for teil in range(len(parts)):
  2.                 if len(parts[teil]) <= 3:
  3.                     if parts[teil] == 'Geo' or parts[teil] == 'GEO' or parts[teil] == 'geo'\
  4.                         or parts[teil] == 'Nat' or parts[teil] == 'NAT' or parts[teil] == 'nat'\
  5.                         or parts[teil] == 'Дом' or parts[teil] == 'ДОМ' or parts[teil] == 'дом'\
  6.                         or parts[teil] == 'Моя' or parts[teil] == 'МОЯ' or parts[teil] == 'моя'\
  7.                         or parts[teil] == 'Кто' or parts[teil] == 'КТО' or parts[teil] == 'кто':
  8.                         parts[teil] = parts[teil].title()
  9.                     else:
  10.                         parts[teil] = parts[teil].upper()
  11.                 else:
  12.                     if parts[teil] != 'JuCe' and parts[teil] != 'TiJi':
  13.                         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.
Sirius3
User
Beiträge: 6097
Registriert: Sonntag 21. Oktober 2012, 17:20

Re: String trennen

Beitragvon Sirius3 » Samstag 4. Februar 2017, 17:33

@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:

  1. SHORT_NAMES_TO_TITLE = {'geo', 'nat', 'дом', 'моя', 'кто'}
  2. LONG_NAMES_TO_IGNORE = {'JuCe', 'TiJi'}
  3.  
  4. [...]
  5.  
  6. renamed_parts = []
  7. for part in parts:
  8.     if len(part) <= 3:
  9.         if part.lower() in SHORT_NAMES_TO_TITLE:
  10.             renamed_parts.append(part.title())
  11.         else:
  12.             renamed_parts.append(part.upper())
  13.     elif part in LONG_NAMES_TO_IGNORE:
  14.         renamed_parts.append(part)
  15.     else:
  16.         renamed_parts.append(part.title())
  17.  
  18. print(*renamed_parts)
Kreser06
User
Beiträge: 16
Registriert: Samstag 21. Januar 2017, 11:49

Re: String trennen

Beitragvon Kreser06 » Samstag 4. Februar 2017, 17:41

Cool, vielen Dank. Das sieht sehr übersichtlich aus.
Aber was soll das bedeuten?

  1. [...]


Ist das ein Platzhalter für den anderen Code?
Benutzeravatar
snafu
User
Beiträge: 5157
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Re: String trennen

Beitragvon snafu » Samstag 4. Februar 2017, 19:40

Kreser06 hat geschrieben:
  1. r'\+\d',                            # +2, +7,
  2. r'\d\.?\d+',                        # 1234, 2.0, 3.123

Falls es eine allgemeine Regex zum Matchen von Floats sein darf:
  1. r'[+-]?\d*\.?\d+'
shcol (Repo | Doc | PyPi)
Kreser06
User
Beiträge: 16
Registriert: Samstag 21. Januar 2017, 11:49

Re: String trennen

Beitragvon Kreser06 » Sonntag 5. Februar 2017, 17:09

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:
  1. main.py - Hauptcode. http://pastebin.com/QcZpPEYy
  2. 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:
  1. Traceback (most recent call last):
  2.   File "/Users/elenakretschmann/Documents/=PYTHON=/Playlist/BBEditRunTemp-main.py", line 34, in <module>
  3.     main()
  4.   File "/Users/elenakretschmann/Documents/=PYTHON=/Playlist/BBEditRunTemp-main.py", line 31, in main
  5.     m3u_dict_anpassen()
  6.   File "/Users/elenakretschmann/Documents/=PYTHON=/Playlist/BBEditRunTemp-main.py", line 25, in m3u_dict_anpassen
  7.     for parts in anpassen.split(anpassen.PATTERNS, liste):
  8. TypeError: split() takes 2 positional arguments but 3 were given

Wie man sieht habe ich aus Dictionary die Namen extrahiert, da ich dachte dass es evtl. daran liegt.
  1.  liste = []
  2.     for key in playlist.m3u_dict.keys():
  3.         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.
Benutzeravatar
__deets__
User
Beiträge: 734
Registriert: Mittwoch 14. Oktober 2015, 14:29

Re: String trennen

Beitragvon __deets__ » Sonntag 5. Februar 2017, 17:39

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.
Kreser06
User
Beiträge: 16
Registriert: Samstag 21. Januar 2017, 11:49

Re: String trennen

Beitragvon Kreser06 » Sonntag 5. Februar 2017, 17:47

ohh man, Danke. :D
Benutzeravatar
snafu
User
Beiträge: 5157
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Re: String trennen

Beitragvon snafu » Sonntag 5. Februar 2017, 20:01

Hier noch ein Verbesserungvorschlag, um den Code etwas pythonischer zu gestalten:
  1. def m3u_to_m3u_dict(self, filename_m3u):
  2.     try:
  3.         with io.open(filename_m3u, 'r', encoding='utf-8-sig') as m3u:
  4.             for zeile in m3u:
  5.                 if zeile.startswith('#EXTINF'):
  6.                     if zeile[11] != '=' and not zeile.startswith('='):
  7.                         name = zeile.rstrip().replace('#EXTINF:-1,','')
  8.                         link = m3u.readline().rstrip()
  9.                         self.m3u_dict[name] = link
  10.     except IOError as error:
  11.         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:
  1. try:
  2.     # ...
  3. except FileNotFoundError:
  4.     msg = 'Die Datei {!r} existiert nicht!'
  5.     print(msg.format(filename_m3u))
  6. except IOError as error:
  7.     print('Fehler beim Öffnen:', error)
shcol (Repo | Doc | PyPi)
Kreser06
User
Beiträge: 16
Registriert: Samstag 21. Januar 2017, 11:49

Re: String trennen

Beitragvon Kreser06 » Sonntag 5. Februar 2017, 20:04

Cool, Danke.
Kreser06
User
Beiträge: 16
Registriert: Samstag 21. Januar 2017, 11:49

Re: String trennen

Beitragvon Kreser06 » Donnerstag 9. Februar 2017, 19:18

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:
  1. def NAME_DICT_ANPASSEN():
  2.     name = playlist.m3u_name_dict
  3.     for parts in anpassen.SPLIT(name):
  4.         print ('xxxxxxxxxxxxx')
  5.         anpassen.GROSS_KLEIN_SCHREIBUNG(parts)


und hier wird es verarbeitet. (for line in name.values():)
  1. def SPLIT(self, name):
  2.         playlist = PLAYLIST()
  3.         patterns = self.PATTERNS
  4.         if isinstance(patterns, dict):
  5.             patterns = patterns.values()
  6.         pattern = re.compile('|'.join(patterns))
  7.         for line in name.values():
  8.             print ('XXXXX ' + line)
  9.             line = re.sub('[\[\(][^\(\)\[\]]*[\]\)]', '', line)         # Klammer und deren Inhalt entfernen
  10.             line = re.sub('(?<!(INT))(?<!(int))[_.-](?!\d)', ' ', line) # Unnötige Sonderzeichen entfernen
  11.             line = line.rstrip()
  12.             yield pattern.findall(line)


Allerdings muss ich jetzt nicht die komplette Dict. weitergeben, sondern jeweils den Wert davon z.B. :

  1. for name in playlist.m3u_name_dict.values():
  2.         print ('v: ' + name)
  3.         anpassen.SPLIT(name)


aber leider passiert mit dem code (SPLIT) nichts. Warum?

hier nochmal Beides:
  1. def NAME_DICT_ANPASSEN():
  2.    
  3.     for name in playlist.m3u_name_dict.values():
  4.         print ('v: ' + name)
  5.         anpassen.SPLIT(name)


und:
  1. def SPLIT(self, name):
  2.         playlist = PLAYLIST()
  3.         patterns = self.PATTERNS
  4.         if isinstance(patterns, dict):
  5.             patterns = patterns.values()
  6.         pattern = re.compile('|'.join(patterns))
  7.         for line in name:
  8.             print ('XXXXX ' + line)
  9.             line = re.sub('[\[\(][^\(\)\[\]]*[\]\)]', '', line)         # Klammer und deren Inhalt entfernen
  10.             line = re.sub('(?<!(INT))(?<!(int))[_.-](?!\d)', ' ', line) # Unnötige Sonderzeichen entfernen
  11.             line = line.rstrip()
  12.             yield pattern.findall(line)


im zweitem Beispiel wird nur print ('v: ' + name) ausgegeben.
Habe ich was übersehen?

Zurück zu „Allgemeine Fragen“

Wer ist online?

Mitglieder in diesem Forum: Google [Bot]