Suche nach bestimmten Buchstaben in einer Textdatei
@YasinSidirva: Ignoriere am besten Alfons' Beiträge. Der provoziert hier öfter unsinnige Diskussionen mit komischen bis falschen Codebeispielen und teils sehr gewagten Thesen seinerseits.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Natürlich hat man Bedingungen, aber Schlüsselworte wie if else sind vermeidbar. Man kann das auch in Python tun. Hier etwa mit einer ifelse Funktion:DasIch hat geschrieben:Nein, tun sie nicht. Lambda Calculus kommt ohne Bedingungen und Schleifen aus. Das spiegelt sich in der Praxis auch durchaus in funktionalen Programmiersprachen wieder.Alfons Mittelmeyer hat geschrieben:Nö, Bedingungen wie if, else, Funktionen def und return sowie Schleifen while, break, continue gehören zu jeder Programmiersprache.kbr hat geschrieben:Wahrscheinlich hast Du auch noch Vorschläge, wie sich if, return und def vermeiden lassen ...
Code: Alles auswählen
# ============ Das gehört nicht auf die Programmebene sondern zur Programmiersprache
def ifelse(condition,execute_if_true,execute_if_false):
if condition:
execute_if_true()
else:
execute_if_false()
# ===========================================================================
value = True
ifelse(value,lambda:print("Wert ist wahr"),lambda:print("Wert ist unwahr"))
value = False
ifelse(value,lambda:print("Wert ist wahr"),lambda:print("Wert ist unwahr"))
Funktionen und while Schleifen sind Elemente höherer Programmiersprachen, um Spaghetti Code zu vermeiden. In früheren Programmiersprachen wie das Commodore BASIC des C64 - (sowie auch ähnlich in Assembler) macht man Funktionen mit gosub Zeilennummer und Schleifen mit goto und zwar rückwärts.DasIch hat geschrieben:Assembler kommt ohne Funktionen und Schleifen aus, findet ebenfalls durchaus praktische Anwendung.
Schleifen gibt es also auch dort, nur nicht schön strukturiert und beliebig umherspringbar. Richtige Funktionen gibt es nicht, da keine Parameterübergabe definiert ist. Das ist wie Funktionen ohne Parameter mit globalen Variablen. Aber man kann implementieren, daß die Parameter auf einem Stack übergeben werden und die sogenannte Funktion hebt sie dann ab.
Code: Alles auswählen
# statt ===
def myfunction_normal(value):
print(value)
myfunction_normal('normal')
# implementiert man dann
stack = []
def myfunction_stack():
print(stack.pop())
stack.append('using stack')
myfunction_stack()
@Alfons Mittelmeyer: Ob reguläre Ausdrücke angebracht sind oder nicht ist eine ermessensfrage, auf jeden Fall sind sie durchaus für solche Aufgaben gedacht und in diesem Fall auch nicht wirklich komplizierterer Code als:
denn:
Das hier:
mag Dir vielleicht simpler und schneller vorkommen als die `startswith()`-Methode, aber es ist nicht ganz äquivalent, weil es einen Fall nicht abdeckt der zu einer Ausnahme führen kann, den `startswith()` allerdings abdeckt. Damit ist das in der Tat qualitativ schlechter. 
kbr benutzt in seiner Funktion für Leute die den ``in``-Operator nicht kennen *keinen* ``in``-Operator. Du fängst hier schon wieder mit einer sehr ”speziellen” Argumentation an. Auf dieser Grundlage könnte man auch monieren, dass der Benutzer den ``in``-Operator nicht kennt und deshalb auch kein `in` im Funktionsnamen vorkommen darf.
Funktionen macht man in BASIC des C64 mit ``DEF FN``. Ist aber nicht sehr gebräuchlich. Mit ``GOSUB`` macht man keine Funktionen — es gibt ja gar keine lokalen Namen und man kann weder Argumente übergeben noch Werte an den Aufrufer zurückgeben. Das sind einfach Unterprogramme die alle auf dem gleichen globalen Namensraum operieren. Mit ``GOTO`` kann man auch den Effekt von Schleifen implementieren, aber nicht nur. Es ist halt eine allgemeine Sprunganweisung. Für Schleifen kennt CBM BASIC V2 allerdings ``FOR``/``TO``/``STEP``/``NEXT``.
Das man den Effekt von Funktionen auf verschiedene Weisen in Maschinensprache implementieren kann, ändert nichts daran das es in der Sprache selbst keine Funktionen gibt. Also zumindest in den allermeisten Befehlssätzen.
@DasIch: Vorsicht mit der zu allgemeinen Aussage zu Assembler und Schleifen — x86 kennt ja beispielsweise ``loop`` und den ``rep``-Präfix.
Code: Alles auswählen
if 'F' in line or 'G' in line or 'M' in line:
Code: Alles auswählen
if re.search('[FGM]', line):
Code: Alles auswählen
if line[0] in 'FGM':

kbr benutzt in seiner Funktion für Leute die den ``in``-Operator nicht kennen *keinen* ``in``-Operator. Du fängst hier schon wieder mit einer sehr ”speziellen” Argumentation an. Auf dieser Grundlage könnte man auch monieren, dass der Benutzer den ``in``-Operator nicht kennt und deshalb auch kein `in` im Funktionsnamen vorkommen darf.

Funktionen macht man in BASIC des C64 mit ``DEF FN``. Ist aber nicht sehr gebräuchlich. Mit ``GOSUB`` macht man keine Funktionen — es gibt ja gar keine lokalen Namen und man kann weder Argumente übergeben noch Werte an den Aufrufer zurückgeben. Das sind einfach Unterprogramme die alle auf dem gleichen globalen Namensraum operieren. Mit ``GOTO`` kann man auch den Effekt von Schleifen implementieren, aber nicht nur. Es ist halt eine allgemeine Sprunganweisung. Für Schleifen kennt CBM BASIC V2 allerdings ``FOR``/``TO``/``STEP``/``NEXT``.
Das man den Effekt von Funktionen auf verschiedene Weisen in Maschinensprache implementieren kann, ändert nichts daran das es in der Sprache selbst keine Funktionen gibt. Also zumindest in den allermeisten Befehlssätzen.
@DasIch: Vorsicht mit der zu allgemeinen Aussage zu Assembler und Schleifen — x86 kennt ja beispielsweise ``loop`` und den ``rep``-Präfix.

-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Das denkst auch nur Du. Es gibt keine Ausnahme, denn alle Zeilen enthalten zumindest ein '\n'. Eine Zeile mit mit nur EOF, würde auch ein Zeichen enthalten, aber diese Zeile taucht bei for l in f gar nicht auf.BlackJack hat geschrieben:@Alfons Mittelmeyer: Ob reguläre Ausdrücke angebracht sind oder nicht ist eine ermessensfrage, auf jeden Fall sind sie durchaus für solche Aufgaben gedacht und in diesem Fall auch nicht wirklich komplizierterer Code als:denn:Code: Alles auswählen
if 'F' in line or 'G' in line or 'M' in line:
Das hier:Code: Alles auswählen
if re.search('[FGM]', line):
mag Dir vielleicht simpler und schneller vorkommen als die `startswith()`-Methode, aber es ist nicht ganz äquivalent, weil es einen Fall nicht abdeckt der zu einer Ausnahme führen kann, den `startswith()` allerdings abdeckt. Damit ist das in der Tat qualitativ schlechter.Code: Alles auswählen
if line[0] in 'FGM':

wieder daneben, es handelte sich um Zeile 2, also: for item in iterable:BlackJack hat geschrieben:kbr benutzt in seiner Funktion für Leute die den ``in``-Operator nicht kennen *keinen* ``in``-Operator. Du fängst hier schon wieder mit einer sehr ”speziellen” Argumentation an. Auf dieser Grundlage könnte man auch monieren, dass der Benutzer den ``in``-Operator nicht kennt und deshalb auch kein `in` im Funktionsnamen vorkommen darf.
Sorry ein GOSUB Label ist ein Funktionsaufruf allerdings parameterlos. Natürlich ist aber Label keine Funktion. Es gibt also parameterlose Funktionsaufrufe aber ohne Definition einer Funktion. Man nennt es auch nicht Funktion sondern Subroutine.BlackJack hat geschrieben:Das man den Effekt von Funktionen auf verschiedene Weisen in Maschinensprache implementieren kann, ändert nichts daran das es in der Sprache selbst keine Funktionen gibt. Also zumindest in den allermeisten Befehlssätzen.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Und Subroutine ist in einem Sinn keine Funktion, denn eine Funktion kann man nur beginnend mit dem Anfang aufrufen, während man bei einer Subroutine auch quer einsteigen kann. Man hat also auch das, was auch höhere Programmiersprachen, nur viel mehr Freiheitsgrade. Und kann tun, was höhere Programmiersprachen ausschließen, weil diese übersichtlichen Code im Sinn haben und nicht erlauben, daß man von einer Funktion mitten in eine andere reinspringt oder daneben springt, weil man vielleicht statt in Code in einem String landet und dann alles crasht, wenn dieser String dann als Code ausgeführt wird. Um das auszuschließen benutzt man in Assembler Label. Wenn man allerdings statt einem Assembler nur einen Maschensprachemonitor hat und dann von Speicherstelle 0xAEEE auf 0xAEA3 zurückspringen muß und das relativ angeben muß also einen negativen Abstand als positiven Wert mit größer 127 ist negativ angeben muß, dann geht es leicht daneben.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Also Funktionen sind nichts Besonderes sondern Einschränkungen und Vieles klappt damit einfach nicht. Etwa hier:
In Funktion function_a will ich genug Platz reservieren, damit ich dann den Code von function_b hineinkopieren kann. Dann will ich function_b löschen und dann function_a aufrufen, um zu testen, ob das geklappt hat.
Aber ich bekomme da einen syntax error. Wie kann ich das machen, damit es funktioniert?
Code: Alles auswählen
def function_a():
' ' * 200
def function_b():
print('soll nach a kopiert werden')
for i in range(len(function_b)):
function_a[i] = function_b[i]
del function_b
function_a()
Aber ich bekomme da einen syntax error. Wie kann ich das machen, damit es funktioniert?
@Alfons Mittelmeyer: kbr verwendet keinen ``in``-Operator. Auch nicht in der zweiten Zeile die Du ja netterweise noch mal hingeschrieben hast. Der ``in``-Operator ist der binäre Operator der testet ob der linke Operand im rechten Operanden vorkommt. Ist zumindest die Implementierung die man erwarten würde. In ``for item in iterable:`` kommt dieser Operator nicht vor.
Ab da drehst Du in den folgenden Beiträgen anscheinend wieder ein bisschen frei.
Ab da drehst Du in den folgenden Beiträgen anscheinend wieder ein bisschen frei.

Code, den ein Anfänger nicht schreiben würde, der jedoch das Problem löst:
Code: Alles auswählen
from __future__ import print_function
from collections import defaultdict, namedtuple
FILENAME = 'input.txt'
NEEDLES = 'G', 'M', 'F'
class Match(namedtuple('Match', 'lineno, line')):
def __str__(self):
return 'Line #{}: {}'.format(
self.lineno, self.line
)
def find_lines(lines, needles):
result = defaultdict(list)
for lineno, line in enumerate(lines, 1):
for needle in needles:
if needle in line:
match = Match(lineno, line.rstrip('\n'))
result[needle].append(match)
return result
def main():
with open(FILENAME) as infile:
result = find_lines(infile, NEEDLES)
for needle in NEEDLES:
print('Matches for {!r}:'.format(needle))
for match in result[needle]:
print(match)
print()
if __name__ == '__main__':
main()
@BlackJack: Du verkennst die Lage. Hier entsteht gerade eine umfassende Python-Dokumentation. Du musst nur noch Themen nach Benutzer suchen 

"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Da noch keine Generatorlösung vorgeschlagen wurde (ja, ich steh' auf die Dinger):
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf-8
from __future__ import with_statement
def main():
with open('input.txt') as ifp, open('output.txt', 'w') as ofp:
ofp.writelines(line for line in ifp if any(e in line for e in 'FGM'))
if __name__ == '__main__':
main()
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Ja stimmt, 'in' in einem Fall ist ein Membership operator und im anderen Fall ein Bestandteil des for statements.BlackJack hat geschrieben:@Alfons Mittelmeyer: kbr verwendet keinen ``in``-Operator. Auch nicht in der zweiten Zeile die Du ja netterweise noch mal hingeschrieben hast. Der ``in``-Operator ist der binäre Operator der testet ob der linke Operand im rechten Operanden vorkommt. Ist zumindest die Implementierung die man erwarten würde. In ``for item in iterable:`` kommt dieser Operator nicht vor.
@ Alfons: "Zuerst alle Python Grundlagen zu studieren ist ach nicht der richtige Rat."
Da sind wir wohl verschiedener Meinung...
"Dem User zu raten, sich zuerst mit Regex zu beschäftigen, trägt nicht zur Problemlösung bei."
Lesen sie nochmal was ich geschrieben habe...
Mit Regex kann man den ganzen Text mit einem Befehl durchsuchen und die gematchten Zeilen speichern. Es gibt natürlich auch andere Wege, aber ich glaube mit Regex ist der Code am kompaktesten.
Da sind wir wohl verschiedener Meinung...
"Dem User zu raten, sich zuerst mit Regex zu beschäftigen, trägt nicht zur Problemlösung bei."
Lesen sie nochmal was ich geschrieben habe...
Mit Regex kann man den ganzen Text mit einem Befehl durchsuchen und die gematchten Zeilen speichern. Es gibt natürlich auch andere Wege, aber ich glaube mit Regex ist der Code am kompaktesten.
Code: Alles auswählen
import re
def write_lines(needles, fn_in, fn_out):
searcher = re.compile('|'.join(needles)).search
with open(fn_in) as infile, open(fn_out, 'w') as outfile:
outfile.writelines(filter(searcher, infile))
if __name__ == '__main__':
write_lines('GMF', 'input.txt', 'output.txt')
@Alfons:
Gerade dann wenn man große Datenmengen verarbeiten muss, ist es schon sinnvoll zu wissen wie man möglichst effizienten Python-Code schreiben kann. Dazu gehört auch die Beschäftigung mit den Sprachmitteln. Sonst kann man's auch lassen und direkt C oder sowas verwenden, wo man jeden Schritt detailliert selbst festlegt und der Compiler es dann für einen optimiert.
Python funktioniert eben so, dass performancekritische Bereiche schon vorkompiliert sind und als (Builtin-)Funktionen dem Programmierer zur Verfügung stehen. Davon sollte bei Bedarf auch reichlich Gebrauch gemacht werden, wenn man die Stärken von Python wirklich ausnutzen will.
Gerade dann wenn man große Datenmengen verarbeiten muss, ist es schon sinnvoll zu wissen wie man möglichst effizienten Python-Code schreiben kann. Dazu gehört auch die Beschäftigung mit den Sprachmitteln. Sonst kann man's auch lassen und direkt C oder sowas verwenden, wo man jeden Schritt detailliert selbst festlegt und der Compiler es dann für einen optimiert.
Python funktioniert eben so, dass performancekritische Bereiche schon vorkompiliert sind und als (Builtin-)Funktionen dem Programmierer zur Verfügung stehen. Davon sollte bei Bedarf auch reichlich Gebrauch gemacht werden, wenn man die Stärken von Python wirklich ausnutzen will.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@snafu: sorry, das ist der einfachste, kompakteste und effizienteste Code für den Fall, daß es der erste Buchstabe wäre: if line[0] in 'FGM':
Sorry, aber die Anforderung ist eine andere. Wenn du die Beispieldaten aufmerksam studierst dann wirst du du sehen, dass der gesuchte Buchstabe nicht zwingend am Zeilenanfang stehen muss. Und selbst wenn es anders wäre, müsstest du noch beweisen welcher Code am effizientesten ist. Dein Bauchgefühl zählt nicht.Alfons Mittelmeyer hat geschrieben:@snafu: sorry, das ist der einfachste, kompakteste und effizienteste Code für den Fall, daß es der erste Buchstabe wäre: if line[0] in 'FGM':
Die von mir vorgeschlagene Lösung ist auch denkbar unter Verwendung von set.intersection(), falls man keine Regex bemühen will:
Dann müssen die needles aber zwingend einzelne Buchstaben sein. Die Regex-Variante ist da flexibler.
Code: Alles auswählen
def write_lines(needles, fn_in, fn_out):
searcher = set(needles).intersection
with open(fn_in) as infile, open(fn_out, 'w') as outfile:
outfile.writelines(filter(searcher, infile))
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@snafu: sorry regex ist ein Matchmonster, siehe Code: ftp.gnupg.org/mutt/regex.c
Das hieße hier mit Kanonen auf Spatzen schließen
in ist eine einfache iteration über alle Elemente einer Liste, die auf c Ebene geschieht und daher wahnsinnig schnell ist.
Auch das ist wahnsinnig schnell und sehr kompakt für nur drei Buchstaben: if 'F' in line or 'G' in line or 'M' in line:
Bei zehn Buchstaben alerdings nicht angebracht.
Deine Lösung mit filter enthält implizit eine Schleife auf Python Ebene, bei der für jedes Element der Liste eine Pythonfunktion, nämlich die filter Funktion aufgerufen wird, das heißt eine relativ ungünstige Laufzeit.
Man kann natürlich seine Pythonkenntnisse ausspielen und einfache Probleme kompliziert und mit geringer Performance implementieren.
Ganz gut gefällt mir dagegen die Generatorlösung von bwbg, die meiner Lösung für mehr als drei Buchstaben entspricht, in kompakterer einzeiliger Schreibweise.
Das hieße hier mit Kanonen auf Spatzen schließen
in ist eine einfache iteration über alle Elemente einer Liste, die auf c Ebene geschieht und daher wahnsinnig schnell ist.
Auch das ist wahnsinnig schnell und sehr kompakt für nur drei Buchstaben: if 'F' in line or 'G' in line or 'M' in line:
Bei zehn Buchstaben alerdings nicht angebracht.
Deine Lösung mit filter enthält implizit eine Schleife auf Python Ebene, bei der für jedes Element der Liste eine Pythonfunktion, nämlich die filter Funktion aufgerufen wird, das heißt eine relativ ungünstige Laufzeit.
Man kann natürlich seine Pythonkenntnisse ausspielen und einfache Probleme kompliziert und mit geringer Performance implementieren.
Ganz gut gefällt mir dagegen die Generatorlösung von bwbg, die meiner Lösung für mehr als drei Buchstaben entspricht, in kompakterer einzeiliger Schreibweise.
@snafu: `re.escape()` wäre bei den `needles` vielleicht ratsam, falls jemand nach irgendwas mit '|', '*', '.', … suchen möchte. 
@Alfons Mittelmeyer: Was hat jetzt der Code von Mutt hier zu suchen? Wenn Du schon auf C-Code verweisen möchtest, dann doch wenigstens auf welchen der etwas Python-relevanter ist.
Wobei: Wenn man mit dem Argument kommt, könnte man auch so ganz allgemein auf die Riesenkanone verweisen, die der C-Quelltext von CPython darstellt. Und das alles nur um Zeilen nach ein paar Buchstaben zu filtern. Das geht in Assembler mit deutlich weniger Code und Speicher, und schneller laufen wird das wohl auch.

@Alfons Mittelmeyer: Was hat jetzt der Code von Mutt hier zu suchen? Wenn Du schon auf C-Code verweisen möchtest, dann doch wenigstens auf welchen der etwas Python-relevanter ist.
Wobei: Wenn man mit dem Argument kommt, könnte man auch so ganz allgemein auf die Riesenkanone verweisen, die der C-Quelltext von CPython darstellt. Und das alles nur um Zeilen nach ein paar Buchstaben zu filtern. Das geht in Assembler mit deutlich weniger Code und Speicher, und schneller laufen wird das wohl auch.

Ja, genau. Im Worst Case dreimal hintereinander den selben Text zu durchlaufen ist unglaublich performant...Alfons Mittelmeyer hat geschrieben:Auch das ist wahnsinnig schnell und sehr kompakt für nur drei Buchstaben: if 'F' in line or 'G' in line or 'M' in line:
Bei zehn Buchstaben alerdings nicht angebracht.
Man merkt immer wieder dass du ein Troll bist.