Hilfe bei UTF-8 Datei auslesen

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

Hallo zusammen,

bin neu hier im Forum und auch Python ist für mich neu. Ich möchte aber gern lernen.

Ich möchte ein kleines Programm schreiben, dass mir meine IPTV Playlist sortiert. Die IPTV Playlist soll später in Enigma2 Receiver eingefügt werden. Allerdings sind die Dateien UTF-8 codiert und da entsteht mein erstes Problem.

Kurz über mein Vorhaben:

Es gibt eine Datei namens "SenderListe.txt" .Diese Datei ist mit UTF-8 gespeichert. Da stehen Namen der Sender und dazugehörige Kanal-Referenz zum Sender und sind mit ";" getrennt..
Da die Playlist für Russische IPTV ist, stehen da Kyrillische Zeichen/Namen drin.

SenderListe.txt:

Code: Alles auswählen

Развлекательные-----;1:64:2:0:0:0:0:0:0:0::
ТНТ;4097:0:1:10:521:D:80130000:0:0:0:
ТНТ4;4097:0:1:60:521:D:80420000:0:0:0:
СТС;4097:0:1:C:521:D:800E0000:0:0:0:
Als erstes wollte ich Die Datei auslesen und in einer Art Datenspeicher sender_liste={} innerhalb des Codes ablegen um später nach Namen im Speicher in einer anderen Datei (Playlist.m3u) zu suchen und entsprechende Kanalreferenz dazuschreiben.

Alledings habe ich schon jetzt Problemme beim Auslesen. Und Zwar ganz am Anfang der ersten Zeile steht : "\ufeff" drin.
und am Ende: "\r\n"
siehe hier:

Code: Alles auswählen

>>> 
============ RESTART: D:\=PYTHON=\Playlist\iptv\playlist_sort.py ============
('\ufeffРазвлекательные-----', '1:64:2:0:0:0:0:0:0:0::\r\n')
('ТНТ', '4097:0:1:10:521:D:80130000:0:0:0:\r\n')
('ТНТ4', '4097:0:1:60:521:D:80420000:0:0:0:\r\n')
('СТС', '4097:0:1:C:521:D:800E0000:0:0:0:')
>>>
Wie kriege ich diese Zeichen ("\ufeff" und "\r\n") weg?
Was muss ich machen um später auf jeweilige Daten zuzugreifen Bsp. sender_liste.name bzw. sender_liste.referenz

hier ist mein Code, aber nicht lachen, wie gesagt das sind meine erste Erfahrungen mit Python/Programmierung.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, sys
import os.path
import codecs
'''-----------------------------CLASSEN--------------------------'''
class Playlist:
    def __init__(self):
        self.filename='SenderListe.txt'
        self.sender_liste={}
        
    def Liste_ins_Speicher(self):
        if os.path.exists(self.filename):
            datei=codecs.open(self.filename, "r", 'utf-8')
            #datei_inhalt=datei.read()
            #print(datei_inhalt)
            #datei_inhalt=codecs.datei_inhalt.decode('utf-8')
            for zeile in datei:
                try:
                    if not zeile:
                        break
                    else:
                        #zeile=zeile.rstrip()
                        parts=zeile.split(';')
                        name=parts[0]
                        referenz=parts[1]
                        self.sender_liste.update({name:referenz})
                except IndexError:
                    continue
            datei.close()

    def Ausgeben(self):
        for i in self.sender_liste.items():
            print(i)

'''-----------------------------CODE--------------------------'''
playlist=Playlist()

playlist.Liste_ins_Speicher()
playlist.Ausgeben()
Ich hoffe ihr könnt mir da weiterhelfen.

Vielen Dank im Voraus.
Zuletzt geändert von Anonymous am Samstag 21. Januar 2017, 12:40, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Kreser06: Das „byte order mark“-Zeichen (BOM) am Anfang wird richtig behandelt wenn man als Kodierung 'utf-8-sig' verwendet. Die beiden Zeichen für die Markierung des Zeilenendes kann man mit der `rstrip()`-Methode loswerden.

Anmerkungen zum Quelltext:

Wenn das für Python 3 ist, dann sollte das in der ersten Zeile auch stehen, also ``python3`` statt nur ``python``.

Zeichenketten sind keine Kommentare, sollten deswegen auch nicht dafür missbraicht werden. Zumal Trennlinien mit Kommentaren wie ``CLASSEN`` und ``CODE`` auch nicht wirklich sinnvoll sind.

Anstelle von `codecs.open()` würde ich `io.open()` verwenden.

Ein Wörterbuch `sender_liste` zu nennen ist ein bisschen verwirrend.

Es ist in Python im allgemeinen unüblich auf die Existenz von Dateien zu testen, denn dieser Test ist im öffnen der Datei bereits enthalten und kann per Ausnahmebehandlung entsprechend behandelt werden. Wenn man das sicherstellen möchte, muss man die Ausnahme so oder so behandeln, denn zwischen einem eigenen Test auf Existenz und dem öffnen der Datei könnte sie gelöscht worden sein.

Die Datei sollte man zusammen mit der ``with``-Anweisung öffnen, statt sie ohne Absicherung gegen Ausnahmen mit `close()` zu schliessen.

Der ``if not zeile:``-Test macht keinen Sinn weil diese Bedingung *nie* erfüllt ist.

Um *einen* Wert zu einem Schlüssel in einem Wörterbuch hinzuzufügen benutzt man nicht `update()` wo man erst einmal ein extra Wörterbuch mit nur einem Eintrag erzeugen muss, sondern man weist dem Schlüssel einfach den Wert zu: ``self.sender_liste[name] = referenz``.

Anstelle des ``continue`` in der Behandlung des `IndexError` reicht ein einfaches ``pass``. ``continue`` würde ich meiden soweit es geht, weil das ein etwas undurchsichtiger Sprung zum Schleifenanfang ist, den man nicht an der Einrückung erkennen kann und der Probleme beim Erweitern des Schleifenkörpers oder auslagern von Teilen in eine eigene Funktion/Methode machen kann.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, oder Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
BlackJack

@Kreser06: Nachtrag: Der Style Guide for Python Code ist lesenswert.

`sys` wird importiert aber nicht verwendet. `os.path` muss nicht importiert werden, das ist ein Attribut des `os`-Moduls das nach import von `os` bereits existiert.

`i` in einer Schleife als Laufvariable für etwas anderes als ganze Zahlen zu verwenden ist keine gute Idee weil damit kein Programmierer rechnet. Einbuchstabige Namen sind in der Regel sowieso nicht aussagekräftig genug für komplexere Werte.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import io


class Playlist(object):

    def __init__(self):
        self.filename = 'SenderListe.txt'
        self.sendernamen2referenz = dict()

    def lade_senderliste(self):
        try:
            with io.open(self.filename, 'r', encoding='utf-8-sig') as datei:
                for zeile in datei:
                    zeile = zeile.rstrip()
                    parts = zeile.split(';')
                    try:
                        name = parts[0]
                        referenz = parts[1]
                        self.sendernamen2referenz[name] = referenz
                    except IndexError:
                        pass
        except EnvironmentError:
            pass  # Ignore I/O errors.

    def ausgeben(self):
        for item in self.sendernamen2referenz.items():
            print(item)


def main():
    playlist = Playlist()
    playlist.lade_senderliste()
    playlist.ausgeben()


if __name__ == '__main__':
    main()
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

danke BlackJack für deine schnelle Hilfe, aber leider geht jetzt Garnichts mehr.
was mache ich falsch? ich habe dein Code genommen, die Datei als "main.py" gespeichert und gestartet. Es wird ein Fehler angezeigt: "invalid character in identifier".
BlackJack

@Kreser06: Wo denn? Den kompletten Traceback bitte.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

habe den Fehler gefunden. Beim kopieren des Codes von der Webseite in die Datei, waren Leerzeichen drin. habe die alle gelöscht und jetzt geht's.
Vielen Dank.

Kannst du mir bitte kurz erklären was der Code bedeutet?

Code: Alles auswählen

if __name__ == '__main__':
    main()
Ich will nur die Vorgehensweise vom Python verstehen.
BlackJack

@Kreser06: `__name__` ist in jedem importierten Modul an eine Zeichenkette mit dem Namen des Moduls gebunden. Nur wenn man ein Modul als Programm ausführt ist es an den Wert '__main__' gebunden. Das heisst man kann das Modul importieren ohne das das Hauptprogramm automatisch ausgeführt wird. Zum Beispiel um Funktionen und Klassen automatisiert oder interaktiv in einer Python-Shell zu testen.
Kreser06
User
Beiträge: 33
Registriert: Samstag 21. Januar 2017, 11:49

Vielen Dank, für deine Hilfe. Jetzt verstehe ich wenigstens etwas mehr : ).
Antworten