Datei bestehend aus Zahlenwerten und zwei Spalten

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.
Antworten
martinr.
User
Beiträge: 3
Registriert: Freitag 16. November 2012, 17:34

Habe ein Problem
habe eine datei erhalten die aus zwei spalten zahlenwerten besteht nun meine frage:
Das öffnen und ausgeben der datei in python ist kein problem.
nur soll die datei ausgelesen werden und auf einen bestimmten zahlenwert durchsucht werden
und pyhton soll eine warnung ausgeben wenn der gesuchte zahlenwert gefunden wird.
bei diesem zahlenwert ist nur die zweite spalte zu durchsuchen
habe mir das so gedacht die datei in eine liste einzufügen und diese liste dann mit einer while funktion
durchsuchen zu lassen.
mein problem ist nur das ich nach einer woche erfolglosen versuchen es nicht schaffte diese datei in eine liste einzufügen.
könnt ihr mir helfen??
Danke für eure antworten
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Hier eine Session mit einer groben Loesung:

Code: Alles auswählen

In [7]: from StringIO import StringIO

In [8]: file_ = StringIO("""42 23
5 32
23 42""")

In [9]: target = '42'

In [10]: for line in file_:
   ....:     first, second = line.split()
   ....:     if second == target:
   ....:         print 'target found'
   ....:         break
   ....:   
target found
Die Datei in eine Liste einzulesen ist unnoetig, wenn du keinen Kontext fuer die Zahl brauchst, also immer nur die aktuelle Zeile wichtig ist. Funktionieren wuerde es aber mit `file.readlines`.
BlackJack

@martinr.: Das sind eigentlich Grundoperationen und wenn man ein Tutorial durchgearbeitet hat, käme man wohl auch nicht auf die Idee eine Liste mit einer ``while``-Schleife zu verarbeiten. Arbeite mal ein Tutorial durch. Zum Beispiel das in der Python-Dokumentation oder für Anfänger wird Learn Python The Hard Way oft empfohlen.

Teile das Problem in kleinere Teilprobleme auf und löse die dann stückweise. Immer erst mit dem nächsten Stück weiter machen, wenn das bisherige Teilprogramm läuft, und das tut was es soll.

Man kann mit einem Programm anfangen was gar nichts tut. Dann eines was die Datei öffnet und die Zeilen ausliest und einfach ausgibt. Testen! Dann so erweitern das die Zeile in ihre Bestandteile aufgeteilt wird und die ausgegeben werden. Testen! Dann nur den Teil mit der zweiten Spalte nehmen und in eine Zahl umwandeln und ausgaben. Testen! Diese Zahl gegen den Suchwert testen und falls die gesuchte Zahl gefunden wurde, das irgendwie in der Ausgabe kenntlich machen. Testen. Jetzt kann man überlegen ob man mit einem ”Flag” arbeiten möchte das man am Anfang mit `False` initialisiert und auf `True` setzt wenn man den Wert gefunden hat, oder ob man das bisherige in eine Funktion steckt und im Fundfall `True` zurück gibt, und im anderen Fall `False`.

Wenn der Test — ob nun per Flag oder als Rückgabewert einer Funktion — wahr ist, kann man eine Warnung ausgeben.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Code: Alles auswählen

from itertools import islice
num = 17
with open('numbers.txt') as fl:
    found = any(float(x)==num for x in islice(fl.read().split(),1,None,2))
martinr.
User
Beiträge: 3
Registriert: Freitag 16. November 2012, 17:34

So hier ist mein programmcode funktioniert wie es soll nur möchte eine kleine verbesserung vornehmen um es dem "nutzer " zu ermöglichen verschieden aufgebaute dateien zu verwenden

Code: Alles auswählen

werte       = open("daten_zweiseitig.txt","r")      # lISTE OEFFNEN
zeilenweise = werte.readline()                      # Daten zeilenweise auslesen
einzelzeile = zeilenweise.strip ()                  # Jede Zeile einzeln auslesen
li          = einzelzeile.split(";")                # Zeile separiern

                             
print "Programm gestartet!"
for li in werte:
    if li [9:19] >= "5,8":
         print "!!!!!!Ueberlast erreicht!!!!!!",li,"\a"
         u = raw_input("druecke Enter zur Kenntnisnahme der Ueberlast")
    else :
        print "Gewicht im Rahmen              ",li
        
b=raw_input("Programm beendet!")
in der for schleife habe ich dem programm vorgeben zwischen welchen indizes das programm den grenzwert suchen soll
nun wäre es natürlich einfacher wenn man einfach sagen könnte suche ab ";" oder eben ab einem anderen trennungszeichen nach diesem grenzwert .
wie bekomme ich das hin ?
danke für eure hilfe
Zuletzt geändert von Anonymous am Montag 26. November 2012, 13:24, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@martinr.: Erst einmal solltest Du das vorhandene Programm korrigieren. Die Kommentare passen teilweise ünerhaupt nicht zu dem was der Code tatsächlich tut. Die Datei wird in der zweiten Zeile zum Beispiel nicht zeilenweise ausgelesen, sondern nur die allererste Zeile wird gelesen.

`strip()` liest auch keine Zeilen. Und ein ``split(';')`` separiert keine Zeilen.

Zudem werden die Werte, die `zeilenweise`, `einzelzeile`, und `li` am Anfang zugewiesen werden, später überhaupt gar nicht verwendet. `li` ist zudem ein schlechter Name. Namen sollten dem Leser die Bedeutung des Wertes dahinter vermitteln. `werte` ist dementsprechend auch kein guter Name, denn auch wenn in der Datei Werte stecken, verarbeitet der Code aus diesem Objekt keine Werte sondern Zeilen (mit Werten).

Bei dem ``if`` vergleichst Du Zeichenketten, was sicher nicht das ist was Du haben möchtest. Beispiel:

Code: Alles auswählen

In [210]: '10,4' > '5,8'
Out[210]: False
Zeichenketten werden zeichenweise lexikografisch verglichen (je nach Zeichenkettentyp nach Bytewert oder Unicode-Codepoint) und das Zeichen '1' ist kleiner als das Zeichen '5', damit ist '10,4' kleiner als '5,8'. Du musst die Werte hier in den richtigen Datentyp, also `float` umwandeln um sie sinnvoll vergleichen zu können.

Werte die nirgends verwendet werden, sollte man entweder gar nicht nicht zuweisen oder das kenntlich machen. Konventionell wird der Name `_`, `dummy`, oder `unused` dafür verwendet, oder man verwendet einen *sinvollen* Namen und stellt dem einen Unterstrich vor (diese Konvention ist nicht so weit verbreitet). Ich würde im Fall von `u` und `b` die Zuweisung einfach komplett weg lassen.

Die letzte Zeile ist nur nötig wenn man ein Kommandozeilenprogramm nicht auf der Kommandozeile startet. Dafür sind die aber gedacht, also sollte man sie dort auch starten und damit ist die Zeile überflüssig. Sie hilft zum Beispiel auch nicht wenn Fehler enthalten sind, die zu einer Ausnahme führen.

Die Frage am Schluss ist sehr vage gestellt. Das bekommt man grundsätzlich hin, in dem man Code schreibt der das tut. Dazu haben Zeichenketten Methoden, die man in solchem Code verwenden kann. Wenn es komplexere Muster sind, kann man die mit dem `re`-Modul ausdrücken. Sollten die Muster *richtig* komplex werden, dann werden reguläre Ausdrücke unlesbar, dann sollte man eine Parsergenerator-Bibliothek wie zum Beispiel `pyparsing` verwenden.

Wenn Teile von so einer Operation variabel sein sollen, macht man diese zu Argumenten einer Funktion, welche die Operation implementiert. Wenn man die ganze Operation flexibel halten möchte, sieht man die Möglichkeit vor, dass eine Funktion an die Funktion übergeben wird, die die Datei verarbeitet.
martinr.
User
Beiträge: 3
Registriert: Freitag 16. November 2012, 17:34

So hab jzt ein bisschen probiert und hoffe jetzt sind die groben schnitzer ausgebessert.

Code: Alles auswählen

import time
z            = raw_input ("Trennzeichen eingeben")
dateisatz  = open ("daten_sprunanregung.txt","r")  
allezeilen  = dateisatz.readline()
einezeile   = allezeilen.strip()
first         = float()
second    = float()
grenzwert = float()
grenzwert ="5,800000"
raw_input ("Programm starten")
for line in dateisatz:
    first, second = line.split (z)
    if second >= grenzwert :
        print"Ueberlast erreicht bei ->", "\a"
        print"Zeit in sec  :"+ first
        print"Spannung in V:"+ second
        time.sleep (2)
    else :
        print"Gewicht im Rahmen!->",first , second
raw_input ("Programm beendet")
 
so hab nun das problem das zwei dateien mit verschiedenen trennzeichen habe , die erste datei ist kein problem da die zwei spalten einfach durch ein ; getrennt werden und durchgehend symmetrisch aufgebaut ist .
Bei dder zweiten datei jedoch ist das trennzeichen ein leerzeichen da aber mehrere an der anzahl unregelmäßig aukommende leerzeichen vorkommen bekomme ich dich meldung das es zu viele dateien wären die geöffnet werden müssten ,da pyhton an jedem leerzeichen trennt .
das ist der grobe aufbau der datei :
0 -0,353099
0,00005 -0,355661
0,0001 -0,351497
0,00015 -0,35438
0,0002 -0,347973
0,00025 -0,349895
0,0003 -0,34605
0,00035 -0,349254
0,0004 -0,347652
0,00045 -0,352458
0,0005 -0,349895
0,00055 -0,355021

dachte daran eine replace funktion anzuweden um die unnötigen leerzeichen in der ersten spalte durch nullen zu ersetzen

Code: Alles auswählen

 line = line.replace(" ",0[0:6])
Danke für eure hilfe bis jetzt und für die weitere :D
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo martin
Hast Du Dein Programm nur einmal laufen lassen???? So wie es da steht ist es voller Fehler.

1) Vor der Klammer "(" bei Funktionsaufrufen wird kein Leerzeichen gesetzt.
2 ) in Python werden keine Variablen deklariert, die Zeilen mit xyz=float() sind also nicht nur überflüssig sonder auch vollkommen unsinnig.
3) Dann setzt du den "grenzwert" als String, so dass der Vergleich >= mit Strings wieder, wie schon von Blackjack beschrieben, unsinnige Ergebnisse liefert.
4) um nach Leerzeichen zu splitten wird ein split ohne Argument verwendet, dann hast Du auch kein Problem mit Leerzeichen am Zeilenanfang, Tabs, usw.
5) alle allezeilen ist eine Liste. Liste haben keine strip-Funktion.
6) das Trennzeichen interaktiv zu lesen, den Dateinamen aber hardcodiert reinschreiben, was macht das für Sinn?

Grüße
Sirius
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Sirius3 hat geschrieben:So wie es da steht ist es voller Fehler.
Nicht alles davon sind echte Fehler, aber es sind einige Abweichungen von Python Style Guide vorhanden. Natürlich kann man von Style Guide abweichen wenn es gute Gründe gibt, aber die Gründe sehe ich hier nicht.

PEP-8 -- Style Guide for Python Code hilft ungemein bei einem konsistenten Stil und ermöglicht es anderen, den Code schneller zu erfassen.
Benutzeravatar
/me
User
Beiträge: 3554
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

martinr. hat geschrieben:So hab jzt ein bisschen probiert und hoffe jetzt sind die groben schnitzer ausgebessert.
Ich ergänze mal die Anmerkungen von Sirius3 (Doppler können vorkommen).

Du öffnest die Datei und schließt sie nicht wieder. Mit with wäre dir das nicht passiert.

Du liest eine Zeile aus der Datei und bindest sie an den Bezeichner allezeilen. Die Zeile ignorierst du damit in der folgenden Schleife völlig. Es mag ja Absicht sein die erste Zeile bei der Verarbeitung zu überspringen, aber das ist nirgendwo dokumentiert und so gehe ich von einem Fehler aus.

Du erstellst aus allezeilen einen String einezeile ohne führende und endende Whitespaces. Anschließend verwendest du diesen Wert nie mehr.

Überflüssiges Binden von Bezeichnern an floats.

Gemeingefährlicher Umgang mit dem Grenzwert. Das muss ein float sein, kein String. Natürlich musst du dann beim Vergleich den eingelesenen Wert auch in ein float konvertieren, aber überlege dir mal was sonst passiert, wenn der eingelesene Wert "10.0000" ist. Dieser Wert würde mit deiner Lösung nicht als Fehler erkannt.

Nach dem Programmaufruf noch mal ein zu bestätigender Hinweis "Programm starten". Ist das Teil eines neuen Evangeliums? "Alles was du von deinem Rechner willst sollst du dreimal mit OK bestätigen!"?

Statt first und second würde ich deskriptive Namen wählen. seconds für die Sekunden und volt für die Spannung.

Die print-Statements kann man mit Stringformatierung schöner gestalten.


Ein erster schneller Entwurf für aufgeräumteren Code sähe dann so aus:

Code: Alles auswählen

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

from __future__ import print_function

import time

grenzwert = 5.8
warning_message = """Überlast erreicht bei ->\a
  Zeit in Sekunden: {seconds}
  Spannung in V   : {volt}"""

with open('daten_sprunanregung.txt', 'r') as datafile:
    for line in datafile:
        seconds, volt = line.split()
        if float(volt.replace(',', '.')) >= grenzwert:
            print(warning_message.format(seconds=seconds, volt=volt))
            time.sleep(2)
        else:
            print('Gewicht im Rahmen! -> {} {}'.format(seconds, volt))
raw_input('Programm beendet')
Ich habe mich jetzt mal nicht um unterschiedliche Trennzeichen gekümmert, da du den Dateinamen ohnehin hart verdrahtet hast. Du könntest dabei aber wie folgt vorgehen. Du liest das Trennzeichen ein. Ist es ein Leerzeichen, dann verwendest du die split-Methode so wie ich sie verwendet habe, also ohne Parameter. In dem Fall werden beliebig viele Whitespaces als Trenner verwendet. Ist das Trennzeichen kein Leerzeichen, dann verwendest du es explizit. Das ist nur eine Fallunterscheidung in der Schleife.

Alternativ könnte man natürlich auch die Datei vorher parsen um den Trenner automatisch durch das Programm feststellen zu lassen.
Antworten