ubuntuusers.de

Python - Wert aus String filtern

Status: Ungelöst | Ubuntu-Version: Kubuntu 11.04 (Natty Narwhal)
Antworten |

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Lies meinen Beitrag noch einmal und insbesondere den Quellcode inklusive der Kommentare 😉 Ob das so passt hättest Du doch locker durch Ausprobieren herausfinden können.

Nobuddy

(Themenstarter)
Avatar von Nobuddy

Anmeldungsdatum:
2. September 2005

Beiträge: 6990

Wohnort: 29614 Soltau

Lysander schrieb:

Lies meinen Beitrag noch einmal und insbesondere den Quellcode inklusive der Kommentare 😉 Ob das so passt hättest Du doch locker durch Ausprobieren herausfinden können.

Das habe ich und das nicht nur einmal. Auch habe ich viele Varianten ausprobiert.

Das

1
result = re.search(regexp, beschreibung).groupdict()

ist der Knackpunkt. Auch wenn Du es beschrieben hast, komme ich nicht dahinter.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Nobuddy schrieb:

Das habe ich und das nicht nur einmal.

Dann hast Du das Compilieren des RegExps an den Beginn der Funktion verlagert oder gar auf Modulebene? 😉 (Ok, das ist nur Kosmetik, aber dennoch sinnvoll!)

Auch habe ich viele Varianten ausprobiert.

Welche denn? Und wieso "probiert"? Hast Du versucht Informationen sinnvoll umzusetzen? Einfach wild rumspielen klappt beim Programmieren eher nicht 😉

Das

1
result = re.search(regexp, beschreibung).groupdict()

ist der Knackpunkt. Auch wenn Du es beschrieben hast, komme ich nicht dahinter.

Da kapiere ich ehrlich gesagt, was daran noch problematisch ist? Ich habe Dir erklärt, wie re.search grob funktioniert bzw. wie die Signatur lautet und was die Methode groupdict auf einem MatchObject tut.

Da musst Du mir erst einmal erklären, wo es noch Probleme gibt, welche das sind und was Du daran nicht kapierst.

Nobuddy

(Themenstarter)
Avatar von Nobuddy

Anmeldungsdatum:
2. September 2005

Beiträge: 6990

Wohnort: 29614 Soltau

Ich war schon am Aufgeben, als ich beim Googeln weitere Infos fand.

Durch meine Unkenntnis, habe mich zu sehr an Dein Beispiel gehalten.

Ich habe jetz die Lösung gefunden, was Deinem Beispiel fast identisch ist.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
with open(quellliste_path, "r") as in_file:
	reader = csv.reader(in_file, delimiter="\t")

	# Zeilenweise aus CSV-Liste auslesen
	for row in reader:
		beschreibung = row[3]
		inhaltsangabe = row[25]
		inhalt = row[26]

		# RegExp
		regexp = re.compile(r"INHALT: ?(?P<VALUE>\d*\.?\d*)\s*(?P<UNIT>\w*)", re.U|re.I)

		# Wenn Spalte inhalt keinen Wert hat
		# Überprüfe, ob in Spalte beschreibung eine Inhaltsangabe enthalten ist
		if inhalt == '':		
			result = re.search(regexp, beschreibung)
			if result != None:
				# Dictionarie
				# Daten in Wörterbuch hinzufügen	
				a = result.groupdict()
				print(a)

Dabei erhalte ich dann auch die Ausgabe in der Art von Dir

Out[35]: {'UNIT': u'BLATT', 'VALUE': u'10'}
Out[35]: {'UNIT': u'', 'VALUE': u'100'}
Out[35]: {'UNIT': u'ST\xdcCK', 'VALUE': u'5'}
Out[35]: {'UNIT': u'', 'VALUE': u'1.650'}

Das Problem lag immer bei mir, daß es mit dem angehängten '.groupdict' nicht funktionierte.

1
result = re.search(regexp, beschreibung).groupdict()

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Nobuddy schrieb:

Das Problem lag immer bei mir, daß es mit dem angehängten '.groupdict' nicht funktionierte.

Ja, dazu hatte ich Dir ja geschrieben, dass man in der Praxis (→ wenn nicht garantiert ist, dass etwas gefunden wird!) prüfen muss, ob es ein Resultat gab. re.search liefert ja bei Erfolg ein MatchObject zurück - auf dem kann man die Methode groupdict ausführen. Wenn nichts gefunden wurde, wird None zurückgeliefert. Und None kennt nun einmal keine Methode groupdict 😉

Du musst Dir mal drigend angewöhnen, eine interaktive Python-Shell neben Deinem Editor offen zu haben, in der Du kleinere Sachen ausprobierst und Stück für Stück entwickelst. Das hilft ungemein. Dort kann man auch nach Herzenslust nach jedem Schritt Dinge an separate Namen binden, um sich die Objekte ausgeben zu lassen oder sonst wie zu analysieren.

Wenn ich Dinge wie foo().bar().noch().was() schreibe, dann kommt das selten bei mir vom Himmel gefallen 😉 Man muss sich klar machen, dass jeder Funktionsaufruf etwas zurückliefert. Bei einigen Funktionen ist das immer None, da die übergebene Objekte direkt manipulieren (random.shuffle z.B.), viele jedoch generieren ein (neues) Objekt, mit welchem Du weiterarbeiten willst. Ich kann solche Aufrufe eben unbegrenzt schachteln, ohne sämtliche Ergebnisse zwischendurch an Namen zu binden:

1
2
3
4
5
6
7
# statt
a = foo()
b = a.bar()
c = b.noch()
d = c.was()
# eben oftmals einfacher
foo().bar().noch().was()

Wenn ich nur an d interessiert bin, dann muss ich mir die Zwischenschritte nicht merken.

Bei Dir ist es nun so, dass re.search manchmal keinen Erfolg hat. Das kann ich direkt abfangen und testen, oder die Exception abfangen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
In [47]: import re

In [49]: res = re.search(r"\d+", "hallo")

In [51]: print res
None

In [52]: res = re.search(r"\d+", "hallo3")

In [53]: print res
<_sre.SRE_Match object at 0xb701c170>

In [54]: def find_digits(text):
   ....:     res = re.search(r"\d+", text)
   ....:     if res:
   ....:         return res.group()
   ....:     
   ....:     

In [55]: find_digits("Hallo123")
Out[55]: '123'

In [56]: find_digits("Hallo")

In [57]: def find_digits(text):
   ....:     try:
   ....:         return re.search(r"\d+", text).group()
   ....:     except AttributeError:
   ....:         return None
   ....:     
   ....:     

In [58]: find_digits("Hallo123")
Out[58]: '123'

In [59]: find_digits("Hallo")

Versuche das einfach mal in einer Shell nachzuvollziehen ☺

(Ich empfehle die Shell ipython, welche Du separat installieren musst)

Nobuddy

(Themenstarter)
Avatar von Nobuddy

Anmeldungsdatum:
2. September 2005

Beiträge: 6990

Wohnort: 29614 Soltau

Hallo Lysander,

Ja, Du hast das geschrieben, habe da aber noch erheblich Probleme mit den Fachbegriffen.

Die Shell ipython habe ich installiert und werde diese zukünftig auch nutzen. 😉

Ich habe den Versuch in einer Shell nachzuvollzogen und werde mich damit weiter beschäftigen.

Mal schauen, wie ich das umgesetzt bekomme.

Grüße Nobuddy

Nobuddy

(Themenstarter)
Avatar von Nobuddy

Anmeldungsdatum:
2. September 2005

Beiträge: 6990

Wohnort: 29614 Soltau

So, seit gestern hat sich doch etwas getan. ☺

Ich habe jetzt das Python-Script soweit, daß nur die richtigen Werte der Inhaltsangabe aus der Beschreibung übernommen werden.

Ich möchte noch dazu erwähnen, daß die Quelliste verschiedene Lieferant mit Ihren Produktdaten beinhaltet.

Da fast jeder Lieferant sein eigenes Ding in Bezug auf Inhaltsangaben macht, habe ich mich dem ersten Lieferanten mit seinen Produktdaten angenommen.

Dies sieht jetzt so aus:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
#!/usr/bin/python3.1
# -*- coding: utf-8

### Import Module
from datetime import date
now = date.today()
heute = now.strftime('%Y.%m.%d-')

import re
import os
import string
import csv



### Basis-Infos
# Quellliste für Lieferanten-Produktdaten
quellliste_subdir = 'daten'	# Ordner für Datei
quellliste_filename = '{}liste.txt'.format(heute)	# Namen der Datei
quellliste_path = os.path.join(os.path.dirname(__file__),  quellliste_subdir, quellliste_filename)	# Pfad zur Datei inklusive Dateinamen
# Zielliste
zielliste_filename = 'testlist.txt'	# Namen der Datei
zielliste_path = os.path.join(os.path.dirname(__file__),  quellliste_subdir, zielliste_filename)	# Pfad zur Datei inklusive Dateinamen


### Programm
# Quelldatei Lieferanten-Produktdaten öffnen
# Kontrolle, ob Quelldatei vorhanden
with open(quellliste_path, "r") as out_file:
	reader = csv.reader(out_file, delimiter="\t")

	# RegExp
	regexp = re.compile(r"INHALT: ?(?P<VALUE>\d*\.?\d*)\s*(?P<UNIT>\w*)", re.U|re.I)

	# Überprüfung, ob Text vorhanden
	# Wenn ja, Ausgabe der numerischen Werte
	def find_digits(text):
		try:
			return re.search(regexp, text).groupdict()
		except AttributeError:
			return None

	# Leere Liste erstellen
	newlist = []

	# Zeilenweise aus CSV-Liste auslesen
	for row in reader:
		lieferant = row[0]
		beschreibung = row[3]
		inhalt = row[26]

		# Verarbeitung von Inhaltsangaben
		# bei Lieferant 048
		if lieferant == '048':
			# Wenn Spalte inhalt keinen Wert hat
			# Überprüfe, ob in Spalte beschreibung eine Inhaltsangabe enthalten ist
			if inhalt == '':
				a = find_digits(beschreibung)
				# Wenn a Wert enthält
				# verarbeite diesen Wert
				if a != None:
					b = a.items()
					c = b[0][1]
					d = b[1][1]
					# Verarbeite Werte, die nicht
					# dem Muster von d entsprechen
					if c != '' and d != 'X' and d != 'JE' and d != 'TINTE' and d != 'ML':
						c = re.sub('\.', '', c)
						# Ersetze die Werte für inhalt
						row[26] = re.sub(row[26], c, row[26])
						# Füge die Zeilen in die Liste newlist ein
						newlist.append(row)
					else:
						# Ersetze die Werte für inhalt
						row[26] = re.sub(row[26], '1', row[26])
						# Füge die Zeilen in die Liste newlist ein
						newlist.append(row)
				else:
					# Ersetze die Werte für inhalt
					row[26] = re.sub(row[26], '1', row[26])
					# Füge die Zeilen in die Liste newlist ein
					newlist.append(row)
			else:
				# Füge die Zeilen in die Liste newlist ein
				newlist.append(row)
		else:
			# Füge die Zeilen in die Liste newlist ein
			newlist.append(row)


# Zieldatei Lieferanten-Produktdaten öffnen
# Kontrolle, ob Zieldatei vorhanden
with open(zielliste_path, "w") as ziel_file:
	reader = csv.reader(ziel_file, delimiter="\t")

	# Vergeb der Liste newlist den Namen a
	a = newlist

	# Lese zeilenweise aus a aus
	for readlines in a:
		# Vergeb für readlines den Namen x
		x = readlines

		# Erstelle das Format für die neue Datei
		text = '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' % (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23], x[24], x[25], x[26])

		# Erstelle die Datei ziel_file
		ziel_file.write(text)

Ich hoffe, daß es nicht zu chaotisch für Euch aussieht.

Für die bessere Verständlichkeit, habe ich Infos im Script dazu geschrieben.

Da ich wirklich noch ein Anfänger in Sachen Python bin, freue ich mich über Vorschläge und Verbesserungen von Euch!

Lysander, hoffe nicht zu viele Fehler habe, die Du als Vollprofi bestimmt finden wirst. 😉

Grüße Nobuddy

Nobuddy

(Themenstarter)
Avatar von Nobuddy

Anmeldungsdatum:
2. September 2005

Beiträge: 6990

Wohnort: 29614 Soltau

Für meinen Nächsten Lieferanten, muß ich für die Suche nach der Inhaltsangabe, die 'regexp' umschreiben.

Dieser macht das nicht so sauber mit 'INHALT:', sondern hier kommt zuerst der Zahlenwert gefolgt mit der Inhaltsangabe (STÜCK, ST, BLATT).

1
regexp = re.compile(r"INHALT: ?(?P<VALUE>\d*\.?\d*)\s*(?P<UNIT>\w*)", re.U|re.I)

Ich habe schon einiges versucht, aus dieser Vorlage eine funktionierende regexp zu bekommen, wo der Zahlenwert zuerst und dann die Inhaltsangabe (STÜCK, ST, BLATT) kommt.

Mit unter habe ich das versucht:

1
regexp = re.compile(r"(d*\.?\d*\<VALUE>P?)\s*(w*\<UNIT>P?)? ST*", re.U|re.I)

, was aber nicht funktioniert.

Inzwischen, habe ich diese Lösung:

1
regexp = re.compile(r"(?P<VALUE>\d*\.?\d*)?ST\s*(?P<UNIT>\w*)", re.U|re.I)

Bin mir da aber nicht sicher, ob dies so wirklich ok ist.

Der Script-Teil sieht für den Anfang mal so aus:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
with open(quellliste_path, "r") as out_file:
	reader = csv.reader(out_file, delimiter="\t")

	# Überprüfung, ob Text vorhanden
	# Wenn ja, Ausgabe der numerischen Werte
	def find_digits(text):
		try:
			return re.search(regexp, text).groupdict()
		except AttributeError:
			return None

	# Zeilenweise aus CSV-Liste auslesen
	for row in reader:
		lieferant = row[0]
		beschreibung = row[3]
		inhalt = row[26]

		# Verarbeitung von Inhaltsangaben
		# bei Lieferant 120
		if lieferant == '120':
			# RegExp
			regexp = re.compile(r"(?P<VALUE>\d*\.?\d*)?ST\s*(?P<UNIT>\w*)", re.U|re.I)

			# Wenn Spalte inhalt keinen Wert hat
			# Überprüfe, ob in Spalte beschreibung eine Inhaltsangabe enthalten ist
			if inhalt == '':
				a = find_digits(beschreibung)
				# Wenn a Wert enthält
				# verarbeite diesen Wert
				if a != None:
					b = a.items()
					c = b[0][1]
					d = b[1][1]
					if c > '0':
						print(b)

Hoffe, daß jemand von Euch, von mir gemachte Fehler mir aufzeigen kann?

Grüße Nobuddy

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Also wenn der RegExp bei Deinen Beispielen klappt, wird er auch funtionieren 😉 Wir können das ohne genau Angabe von möglichen Fällen sonst nicht beantworten.

Mir fällt auf, dass Du den RegExp erst nach Definition der Inline-Funktion kompilierst und an einen Namen bindest. Das solltest Du global zu Beginn eines Moduls machen - globale Variablen sollte man grundsätzlich vermeiden, aber kompilierte reguläre Ausdürcke bilden da oftmals eine Ausnahme (kann natürlich auch eine Klasse sein oder auch eine Funktion).

Generell fällt mir auf, dass Du immer noch nicht mit vier Spaces als Einrückung arbeitest. Bitte stelle endlich darauf, um da es PEP8 entspricht und man Deinen Code dann besser lesen kann.

Zudem solltest Du Dich dringend mit Funktionen befassen. Python (wie so ziemlich jede Programmiersprache) lebt von Modularisierung. Man muss komplexe Abläufe in möglichst kleine, universelle Schritte unterteilen, die man dann entsprechend durch Funktionsaufrufe zusammenfasst. Du hast in Deinem langen Script sieben Einrückungsebenen; das kann man zwar nicht pauschal als schlecht auffassen, aber vieles deutet darauf hin, dass Du da zu viel auf einmal versuchst.

Schau Dir mal mein Script aus diesem Thread an. Du hättest das alles auf Modulebene und in zig Schleifen verpackt umgesetzt. Ich habe es in kleine, handliche und vor allem separat zu testende Funktionen verpackt. Natürlich kannst Du das nicht 1:1 übernehmen, aber es soll Dir einen Eindruck davon vermitteln, wo Du hin willst. Ich habe eine Funktion, die über die Zeilen einer Datei iteriert. Wieso habe ich das getan? Ganz einfach, weil ich eine Funktion scan_blocks brauche, die Zeilen übergeben bekommt und aus diesen zusammenhängende Blöcke filtert. Ich hätte dieser auch den Dateinamen übergeben können, sie hätte dann die datei öffnen und über die Zeilen iterieren können. Kein großes Problem an sich. Aber: So kann ich die Funktion testen, ohne eine Datei mit Daten anlegen zu müssen! Ich kann also ganz einfach in einer Shell die Funktionalität testen, ohne mich erst mit Dateihandling und dem dazugehörigen Overhead befassen zu müssen. Zudem kann ich die Funktion später auch mit anderen Datenquellen als einer Datei nutzen; evtl. kommen Daten dann aus einer Datenbank oder ich habe sie in einer JSON-Datei oder oder oder.

Bei Dir weiß ich noch nicht, wie Dein Konzept an sich aussieht, insofern kann ich pauschal schlecht sagen, wie Du sinnvoll strukturieren solltest. Ich könnte mir grob vorstellen, dass Du spezielle Suchfunktionen je nach Eingangsformat (vom Lieferenaten bahängig?) bauen musst, die aber auf einem generischen Suchablauf und einer gemeinsamen Zieldatenstruktur basieren.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

1
2
3
4
5
# das:
text = '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' % (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23], x[24], x[25], x[26])
# ist umständlich!
# geht doch so viel einfacher:
text = '\t'.join(x)

Davon mal abgesehen: Wieso nutzt Du das csv-Modul nicht auch zum Schreiben? Wieso bindest Du ständig vorhandene Objekte an andere Namen? Du kannst doch einfach den einen Namen benutzen... (zumal x echt nichts aussagt! - Namen sollten möglichst viel über das Objekt aussagen, an welches sie gebunden sind!)

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Noch etwas: Kannst Du mal eine Testdatei posten, mit der Dein Script funktioniert? Mit den Daten aus Deinem ersten Posting bekomme ich mit Deinem Code einen IndexError:

1
2
3
4
5
6
nelson@MECL-LAP3:~/src/Python/forum/lieferanten$ ./parser.py lieferliste.csv
['3M POST-IT INDEX MUSTERKARTE, INHALT: 25 ST\xc3\x9cCK  \xc3\x9cBERZEUGEN SIE IHRE KUNDEN !   ']
Traceback (most recent call last):
  File "./parser.py", line 51, in <module>
    beschreibung = row[3]
IndexError: list index out of range

Nobuddy

(Themenstarter)
Avatar von Nobuddy

Anmeldungsdatum:
2. September 2005

Beiträge: 6990

Wohnort: 29614 Soltau

Lysander schrieb:

Also wenn der RegExp bei Deinen Beispielen klappt, wird er auch funtionieren 😉 Wir können das ohne genau Angabe von möglichen Fällen sonst nicht beantworten.

Nein klappt noch nicht ganz, poste später Beispieldaten und Angaben.

Mir fällt auf, dass Du den RegExp erst nach Definition der Inline-Funktion kompilierst und an einen Namen bindest. Das solltest Du global zu Beginn eines Moduls machen - globale Variablen sollte man grundsätzlich vermeiden, aber kompilierte reguläre Ausdürcke bilden da oftmals eine Ausnahme (kann natürlich auch eine Klasse sein oder auch eine Funktion).

In dem Fall muß ich das RegExp lieferantenspezifisch anwenden.

Generell fällt mir auf, dass Du immer noch nicht mit vier Spaces als Einrückung arbeitest. Bitte stelle endlich darauf, um da es PEP8 entspricht und man Deinen Code dann besser lesen kann.

Zudem solltest Du Dich dringend mit Funktionen befassen. Python (wie so ziemlich jede Programmiersprache) lebt von Modularisierung. Man muss komplexe Abläufe in möglichst kleine, universelle Schritte unterteilen, die man dann entsprechend durch Funktionsaufrufe zusammenfasst. Du hast in Deinem langen Script sieben Einrückungsebenen; das kann man zwar nicht pauschal als schlecht auffassen, aber vieles deutet darauf hin, dass Du da zu viel auf einmal versuchst.

Ja, da habe ich noch einiges zu lernen.

Schau Dir mal mein Script aus diesem Thread an. Du hättest das alles auf Modulebene und in zig Schleifen verpackt umgesetzt. Ich habe es in kleine, handliche und vor allem separat zu testende Funktionen verpackt. Natürlich kannst Du das nicht 1:1 übernehmen, aber es soll Dir einen Eindruck davon vermitteln, wo Du hin willst. Ich habe eine Funktion, die über die Zeilen einer Datei iteriert. Wieso habe ich das getan? Ganz einfach, weil ich eine Funktion scan_blocks brauche, die Zeilen übergeben bekommt und aus diesen zusammenhängende Blöcke filtert. Ich hätte dieser auch den Dateinamen übergeben können, sie hätte dann die datei öffnen und über die Zeilen iterieren können. Kein großes Problem an sich. Aber: So kann ich die Funktion testen, ohne eine Datei mit Daten anlegen zu müssen! Ich kann also ganz einfach in einer Shell die Funktionalität testen, ohne mich erst mit Dateihandling und dem dazugehörigen Overhead befassen zu müssen. Zudem kann ich die Funktion später auch mit anderen Datenquellen als einer Datei nutzen; evtl. kommen Daten dann aus einer Datenbank oder ich habe sie in einer JSON-Datei oder oder oder.

Werde ich mir anschauen.

Bei Dir weiß ich noch nicht, wie Dein Konzept an sich aussieht, insofern kann ich pauschal schlecht sagen, wie Du sinnvoll strukturieren solltest. Ich könnte mir grob vorstellen, dass Du spezielle Suchfunktionen je nach Eingangsformat (vom Lieferenaten bahängig?) bauen musst, die aber auf einem generischen Suchablauf und einer gemeinsamen Zieldatenstruktur basieren.

Ja, vieles ist lieferantenabhängig, das Ziel ist die gemeinsame Zieldatenstruktur.

Bin noch in der Lernphase, stelle aber fest, daß ich jetzt schon vieles einfacher angehe, als noch vor einiger Zeit.

Nobuddy

(Themenstarter)
Avatar von Nobuddy

Anmeldungsdatum:
2. September 2005

Beiträge: 6990

Wohnort: 29614 Soltau

Lysander schrieb:

1
2
3
4
5
# das:
text = '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' % (x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23], x[24], x[25], x[26])
# ist umständlich!
# geht doch so viel einfacher:
text = '\t'.join(x)

Davon mal abgesehen: Wieso nutzt Du das csv-Modul nicht auch zum Schreiben? Wieso bindest Du ständig vorhandene Objekte an andere Namen? Du kannst doch einfach den einen Namen benutzen... (zumal x echt nichts aussagt! - Namen sollten möglichst viel über das Objekt aussagen, an welches sie gebunden sind!)

Ich muß wirklich da mal richtig das csv-Modul durchlesen.

Das ist ja um vieles einfacher und die Gefahr von Fehlern, reduzieren sich dadurch!

Danke 👍

PS: Habe festgestellt, daß der Zeilenumbruch '\n' fehlt.

Habe beim Googel noch nichts gefunden, wo dies behandelt wird.

Gibt es dafür eine Lösung?

Nobuddy

(Themenstarter)
Avatar von Nobuddy

Anmeldungsdatum:
2. September 2005

Beiträge: 6990

Wohnort: 29614 Soltau

Ich habe hier mal von dem Lieferanten 120, einen kleinen Auszug:

120	10555780	TESA KLEBESTÜCKE TACK 200ST TRANSP.   BIG PAC	TESA KLEBESTÜCKE TACK 200ST TRANSP.   BIG PAC 	TESA	594010000000	VE	1	2	1	4,75	6,50								04042448042750	09	36	488		LAGER		1
120	10555869	LEITZ HEFTKLAMMERN JUWEL 2000 STÜCK	LEITZ HEFTKLAMMERN JUWEL 2000 STÜCK 	LEITZ	56400000	VE	1	2	1	1,17	1,49								04002432396689	09	27	470		LAGER		1
120	10555975	DURABLE SICHTTAFEL A4 BLAU PACKUNG MIT 5 STÜCK	DURABLE SICHTTAFEL A4 BLAU PACKUNG MIT 5 STÜCK 	DURABLE	560706	VE	1	2	1	13,23	17,45								04005546560762	08	90	432		LAGER		1
120	10544690	LEITZ HÄNGETASCHE ALPHA SCHWARZ 5 STÜCK	LEITZ HÄNGETASCHE ALPHA SCHWARZ 5 STÜCK LEITZ 1926-30-95 ACTIVE PG5ST	LEITZ	19263095	VE	1	2	1	6,35	8,09								04002432392087	08	12	369		LAGER		1
120	10547974	HERMA SPECIAL ETIKETT 210X148MM WEISS 50 STÜCK	HERMA SPECIAL ETIKETT 210X148MM WEISS 50 STÜCK HERMA 10910  25X2=50ST	HERMA	10910	VE	1	2	1	5,83	7,75					7,15	3		04008705109109	02	60	102		LAGER		1
120	10555381	ALCO FLACHKOPFKLAMMER 100ST MESSING   16MM	ALCO FLACHKOPFKLAMMER 100ST MESSING   16MM 	ALCO	59041	VE	1	2	1	1,73	2,40								04007735590413	09	09	527		LAGER		100
120	10555382	ALCO RUNDKOPFKLAMMER 17MM MESSING   100ST	ALCO RUNDKOPFKLAMMER 17MM MESSING   100ST 	ALCO	331	VE	1	2	1	1,26	1,80								04007735003319	10	10	527		LAGER		100
120	11310366	ACTUS AKTENFAHNE LANG DKL.GRÜN PACK MIT 100 ST	ACTUS AKTENFAHNE LANG DKL.GRÜN PACK MIT 100 ST 4-FACH GELOCHT	ACTUS	1050107	VE	1	2	1	10,41	13,24	2	10,25	9,59	5	12,99	2		04250097668416	08	96	0		LAGER		1
120	11320197	ESSELTE SICHTHÜLLEN A5 STANDARD 0,12 MM, 100 ST	ESSELTE SICHTHÜLLEN A5 STANDARD 0,12 MM, 100 ST 	ESSELTE	54850	VE	1	2	1	5,36	6,85								05701216548502	08	87	366		LAGER		1
120	16913162	POST-IT POST-IT RECYC.NOTES 654 GELB 16 X 100 BL	POST-IT POST-IT RECYC.NOTES 654 GELB 16 X 100 BL 76 X 76 MM TOWER-PACK	3M	6541T	VE	1	2	1	14,36	18,39								04046719100651	13	40	664		LAGER		1
120	16913163	POST-IT POST-IT RECYC.NOTES 655 GELB 16X100 BL	POST-IT POST-IT RECYC.NOTES 655 GELB 16X100 BL 127 X 76 MM TOWER-PACK	3M	6551T	VE	1	2	1	18,97	24,29								04046719100682	13	40	664		LAGER		1

Nach reiflicher Überlegung, bin ich hier zu dem Entschluß gekommen, dies zuerst anderst anzugehen.

Grund dafür ist, daß manche Produkte trotz der Inhaltsangabe z.B. '100BL', als '1' zu führen sind.

Um die ganze Komplexität, bezüglich dieses Lieferant in den Griff zu bekommen, bräuchte ich die 'eierlegende Wollmilchsau'. 😉

Ich habe einen Lieferanten, der entsprechende Inhaltsangaben in einer gesonderten Spalte hat.

Weiter habe ich den Lieferanten 048, mit ich aus der Beschreibung die Inhaltsangabe 'INHALT:' herausfiltern konnte.

Mein Gedanke geht nun dahin, daß bei allen Lieferanten, der Hersteller, die Herstellernummer und der EAN-Code (nicht bei allen Produkten) vorhanden ist.

Ich habe schon im Vorfeld, die Lieferantendaten in eine gemeinsame Datei überführt, wo ich mich für ein bestimmtes Datenformat entschieden habe.

Dieses Datenformat sieht folgendermaßen aus:

1. Alles ist in Großbuchstaben umgewandelt!

2. Hersteller mit Mehrfachnamen sind durch Bindestrich verbunden, Leerzeichen gibt es nicht!

3. Bei der Herstellernummer wurden alle Leerzeichen, sowie Sonderzeichen (/.,_- usw.) entfernt!

4. Der EAN-Code hat ein 13-stelliges Format!

Nun werde ich bei Lieferant 120 nicht die 'eierlegende Wollmilchsau' herauslassen, sondern stelle einen Vergleich zu den anderen Lieferantendaten her, wo der Herstellernamen und die Herstellernummer die Basis bilden. Dadurch dürfte ich etliche Daten bei Lieferant 120 bereinigt bekommen.

Der zweite Schritt ist dann der Vergleich des EAN-Codes, um Daten bei Lieferant 120 bereinigt zu bekommen.

Die übrig gebliebenen Datensätze von Lieferant 120, werde ich dann duch Filterung (ST, STÜCK, BL, BLATT) versuchen zu bereinigen.

Sobald ich den ersten Ansatz habe, melde ich mich wieder!

Grüße Nobuddy

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Hört sich erst einmal ganz sinnvoll an, wobei klar ist, dass man bei "n"-Formaten "n"-Konverter benötigt.

Nobuddy schrieb:

Dieses Datenformat sieht folgendermaßen aus:

Du musst Dich bei Python von den rein Datei zentrierten "Datentypen" trennen. Letztlich sind das (Text-)Formate für Persistenzen; da würde ich sowieso auf ein etabliertes Format a la JSON, XML, CSV usw. setzen. Hängt ein wenig vom Anwendungsfall ab. Du brauchst vor allem eine interne Repräsentation mit Hilfe der Datentypen von Python. Das kann im einfachsten Falle eine Liste von Dictionaries sein, oder gar NamedTuples oder sogar Klassen.

Ich weiß, dass Du hier grad über eine "zentrale" Registerdatei sprichst, die Du bereits hast... aber bei Deiner Vorgehensweise solltest Du Dir schon überlegen, dass Du da das Parsen und den inhatlichen Abgleich nicht vermischst.

Grundsätzlich ist mir der komplette Anwendungsfall noch im Dunkeln. Wenn ich etwas von EAN höre, dann denke ich erst einmal an eine ID, die Hersteller unabhängig ist. Wenn dem so ist, so sollte diese auch nicht mit einem Hersteller fix verbunden sein. Zudem wäre das ein Produkt / Artikel, welcher bestimmte Kriterien eben Hersteller / Lieferanten unabhängig besitzt. Dazu kommen dann noch Attribute, die vom Lieferanten abhängig sind, etwa der Preis. In Deinen Datensätzen - wo auch immer die herkommen - ist das ziemlich vermischt. Nun ist die Frage, ob ich hier richtig liege, dass Du das alles konsolidieren willst. Wenn ja, ist die inhaltliche und interne Darstellung der Daten der erste Schritt. Danach kann ich mir Gedanken machen, wie ich die Daten aus den Dateien extrahiere.