Verbesserungsvorschläge für mein Python Skript: Polindrome finden?
Hey,
ich habe heute ein kleines Python Skript geschrieben, um Polindrome in einer Textdatei zu erkennen. Polindrome sind Wörter, die rückwärts geschrieben genau den gleichen Sinn ergeben wie vorwärts geschrieben.
#!/bin/python3
#Polindrome-Woerter in Textdatei erkennen
import string
#Funktion zum Erkennen von Polindromen
def check_polindrome(word):
reverse = ''
removable = ['\n', '\t', '\r']
for c in removable: # Zeug entfernen
word = word.replace(c, '')
for c in string.punctuation: #Sonderzeichen entfernen
word = word.replace(c, '')
for c in string.whitespace: #Leerzeichen entfernen, da sonst falsche Ergebnisse entstehen
word = word.replace(c, '')
if word in string.punctuation or word in string.whitespace: #Leer- und Sonderzeichen abfangen
return False
if word.isdigit() == True: #Zahlen abfangen, da z.B. 121 rueckwaerts auch 121 ergibt
return False
for i in range(len(word)-1, 0-1, -1): #Wort rueckwaerts zusammen basteln
reverse = reverse + word[i]
if reverse.lower() == word.lower(): #Rueckwaerts-Wort mit vorwaerts-Wort vergleichen
return True
else:
return False
#Den Benutzer eine Textdatei oeffnen lassen
file = input('Path to file: ')
polindrome = []
try:
with open(file, 'r') as f:
lines = f.readlines()
except FileNotFoundError:
print('File not found!')
exit(0)
#Einzelne Woerter im Text der Funktion check_polindrome uebergeben
for i in range(0, len(lines)):
lines[i] = lines[i].split(' ')
for word in lines[i]:
if check_polindrome(word) == True:
polindrome.append(word)
else:
continue
#Ergebnis anzeigen
print(len(polindrome), ' found!\n')
for i in range(len(polindrome)):
print(polindrome[i].replace('\n', '')) #\n in Wort entfernen, da sonst zu viele Leerzeichen bei Output
Die Projektidee habe ich von: https://www.gutefrage.net/frage/python-projekt-ideen#answer-357880884
Wie man rückwärts über eine Zeichenkette rotiert, habe ich von: https://stackoverflow.com/questions/7961499/best-way-to-loop-over-a-python-string-backwards
- Hat jemand Verbesserungsvorschläge für meinen Code?
- Ein kleines Feedback bitte
2 Antworten
Erstens: es heißt Palindrom.
Zweitens, nur ein paar eher schnelle Beobachtungen.
for i in range(len(word)-1, 0-1, -1): #Wort rueckwaerts zusammen basteln
reverse = reverse + word[i]
Klar, kann man machen, aber das geht auch viel einfacher:
>>> w = "nasenbär"
>>> w[::-1]
'räbnesan'
Das hier:
for c in removable: # Zeug entfernen
word = word.replace(c, '')
for c in string.punctuation: #Sonderzeichen entfernen
word = word.replace(c, '')
for c in string.whitespace: #Leerzeichen entfernen, da sonst falsche Ergebnisse entstehen
word = word.replace(c, '')
Kann man auch vereinfachen, indem man erst eine Übermenge aller dieser Listen/Sets bildet und dann einmal durchgeht. Du kannst dir auch str.translate() anschauen.
Sowas in der Art:
if ein_boolescher_ausdruck
return True
else:
return False
ist unnötig kompliziert. Du kannst doch den booleschen Wert direkt zurückgeben.
Das hier:
if check_polindrome(word) == True:
polindrome.append(word)
else:
continue
lässt sich eindampfen auf:
if check_polindrome(word):
polindrome.append(word)
Das hier:
for i in range(0, len(lines)):
brauchst du allenfalls, wenn du den Index mitzählen willst. Über eine Liste (oder sonst ein iterable) kannst du doch viel einfacher iterieren:
for line in lines:
# tu was mit line
Verbesserter Code:
#!/bin/python3
#Palindrome-Woerter in Textdatei erkennen
import string
#Funktion zum Erkennen von Palindromen
def check_palindrome(word):
reverse = ''
removable = string.punctuation + string.whitespace + string.digits
for c in removable: #Leerzeichen entfernen, da sonst falsche Ergebnisse entstehen
word = word.replace(c, '')
if word in string.punctuation or word in string.whitespace: #Leer- und Sonderzeichen abfangen
return False
for c in word[::-1]: #Wort rueckwaerts zusammen basteln
reverse = reverse + c
if reverse.lower() == word.lower(): #Rueckwaerts-Wort mit vorwaerts-Wort vergleichen
return True
else:
return False
#Den Benutzer eine Textdatei oeffnen lassen
file = input('Path to file: ')
palindrome = []
try:
with open(file, 'r') as f:
lines = f.readlines()
except FileNotFoundError:
print('File not found!')
exit(0)
#Einzelne Woerter im Text der Funktion check_palindrome uebergeben
for line in lines:
line = line.split(' ')
for word in line:
if check_palindrome(word):
palindrome.append(word)
else:
continue
#Ergebnis anzeigen
print(len(palindrome), ' found!\n')
for i in range(len(palindrome)):
print(palindrome[i].replace('\n', '')) #\n in Wort entfernen, da sonst zu viele Leerzeichen bei Output
Wenn ich aber
line = line.split(' ')
nicht mache, dann bekomme ich den gesamten Text in einzelnen Buchstaben im Output.
alfredo hat schon das Meiste gesagt. Hier noch ein paar konkrete Tipps:
#!/usr/bin/env python3
(siehe hier)
#Funktion zum Erkennen von Polindromen
def check_polindrome(word):
reverse = ''
# 1. brauchst du nicht, denn das ist alles whitespace:
#removable = ['\n', '\t', '\r']
#for c in removable: # Zeug entfernen
# word = word.replace(c, '')
# 2. kann man machen, ist aber teuer.
# Verwende lieber str.translate():
#for c in string.punctuation: #Sonderzeichen entfernen
# word = word.replace(c, '')
#for c in string.whitespace: #Leerzeichen entfernen, da sonst falsche Ergebnisse entstehen
# word = word.replace(c, '')
word = word.translate(str.maketrans('', '', string.punctuation))
# 3. Unnötig, denn du hast diese Zeichen eben gelöscht.
# Effektiv prüfst du hier nur, ob word=="".
#if word in string.punctuation or word in string.whitespace: #Leer- und Sonderzeichen abfangen
# return False
# 4. Huch? Warum soll 121 kein Palindrom sein?
#if word.isdigit() == True: #Zahlen abfangen, da z.B. 121 rueckwaerts auch 121 ergibt
# return False
# 5. geht simpler mit reverse=word[::-1]
#for i in range(len(word)-1, 0-1, -1): #Wort rueckwaerts zusammen basteln
# reverse = reverse + word[i]
# zu 3 und 4: Wenn du unbedingt willst, kannst du die
# Spezialfälle auch hier aussondern:
return ( word != '' # kein leeres Wort
and not word.isdigit() # keine Zahlen
and word[::-1].lower() == word.lower(): #Rueckwaerts-Wort mit vorwaerts-Wort vergleichen
)
try:
with open(file, 'r') as f:
# 6. Warum willst du eine 100 TB große Textdatei
# auf einmal lesen?
#lines = f.readlines()
# Eine einzelne Zeile ist doch mehr als genug.
# Auch Zeilen können ziemlich lang sein, aber ich
# kenne keine Methode, einzelne Wörter zu lesen.
for line in f:
#Einzelne Woerter im Text der Funktion check_polindrome uebergeben
# 7. split() ohne Argument trennt bei jeder
# Folge von Whitespace. Das reicht hier völlig.
# Außerdem musst Du dann beim Check keinen
# Whitespace mehr entfernen:
for word in line.split():
if check_polindrome(word):
polindrome.append(word)
except FileNotFoundError:
print('File not found!')
# 8. exit(0) hieße "alles in Ordnung".
exit(1)
...der letzte Fall ist auch zweifelhaft, weil du hier durch die Liste an Lines durchiterierst und sie gleichzeitig veränderst. Mach das nicht. Es ist auch gar nicht nötig.