Seite 1 von 1
ein Teilstring finden
Verfasst: Freitag 26. Mai 2017, 19:44
von Leny
Hallo,
ich habe bereits diverse Foren durchsucht und bin nicht so richtig findig geworden. Mein Ziel ist folgendes ich muss ein String durchsuchen und alle
#Keywords in einem separatem String abspeichern.
Die zu durchsuchenden Strings bekomme ich aus einer CSV Datei.
Mein Problem ist, dass beim Durchlaufen von String nicht immer alle #Keywords gefunden werden.
Das Ist mein Code:
Code: Alles auswählen
str="#Polls #slipping, have HER camp on defense/lowering expectations, going into #Debates2016"
str3="#MaryBrigidMcManamon, Washington Post: Constitutionally speaking, #Cruz simply isnt eligible to be president"
laenge = 0
keyword=''
while laenge < len(str):
if str[laenge]=='#':
index_hashtag = laenge
hash=True
if str[index_hashtag+1]=='#' or str[index_hashtag+1]==' ':
laenge= index_hashtag+2
hash=False
if str[laenge]==' ' or str[laenge]=='.' or str[laenge]==',' or str[laenge]==str[len(str)-1]:
index_leerZ=laenge
leerZ=True
laenge += 1
if hash==True and leerZ==True:
keyword=keyword+str[index_hashtag:index_leerZ]
hash = False
leerZ = False
print keyword
laenge+=1
wenn ich str3 durchsuche, werden alle #keyword gefunden (#MaryBrigidMcManamon #Cruz)
wenn ich str durchsuche, wird immer nur das erste #keyword gefunden. (#Polls oder #slipping, je nach dem dem was als erste steht)
ich kann überhaupt nicht nachvollziehen, warum es beim einen klappt und beim anderen nicht.
Würde mich sehr freuen, wenn ihr vielleicht Ideen dazu habt.
Vielen Dank
Re: ein Teilstring finden
Verfasst: Freitag 26. Mai 2017, 21:33
von Sirius3
@Leny: was macht den zweiten #hastag im ersten String besonders? Wie wird das Ende bestimmt?
PS: für sowas verwendet man reguläre Ausdrücke.
Re: ein Teilstring finden
Verfasst: Freitag 26. Mai 2017, 22:15
von Leny
zwischendurch habe ich mein Code korrigiert:
Code: Alles auswählen
# -*- coding: utf-8 -*-
import csv
with open('new.csv', 'wb') as newcsv:
csvfile = open("american-election-tweets2.csv", "rb")
reader = csv.DictReader(csvfile.read().decode('utf-8-sig').encode('utf-8').splitlines(), delimiter=';')
fieldnames = ['handle', 'text', 'is_retweet', 'original_author', 'time', 'in_reply_to_screen_name',
'retweet_count', 'favorite_count', 'hashtag']
writer = csv.DictWriter(newcsv, fieldnames=fieldnames, delimiter=';')
writer.writeheader()
num=0
for row in reader:
laenge = 0
keywords = []
row['text']=row['text'].strip('\xe2\x80\xa6')
for laenge in range(len(row['text'])):
if row['text'][laenge] == '#':
index_hashtag = laenge
hash = True
if row['text'][index_hashtag + 1] == '#' or row['text'][index_hashtag + 1] == ' ':
laenge = index_hashtag + 2
hash = False
if row['text'][laenge] == ' ' or row['text'][laenge] == '.' or row['text'][laenge] == ',' \
or row['text'][laenge] == row['text'][len(row['text']) - 1] or row['text'][laenge] == '"' \
or row['text'][laenge] == '!' or row['text'][laenge] == ':' or row['text'][laenge] == '-' or \
row['text'][laenge] == "'":
if laenge == len(row['text']) - 1: laenge += 1
leerZ = True
if hash == True:
keywords.append(row['text'][index_hashtag:laenge])
hash = False
leerZ = False
print (row['text'][index_hashtag])
print (row['text'][laenge-1])
print keywords
writer.writerow({'handle': row['handle'], 'text': row['text'], 'is_retweet': row['is_retweet'],'original_author': row['original_author'],
'time': row['time'],'in_reply_to_screen_name': row['in_reply_to_screen_name'],'retweet_count': row['retweet_count'],
'favorite_count': row['favorite_count'],'hashtag': keywords})
keywords=[]
hier wird eine csv Datei (mit verschiedenen spalten, eine davon ist text) zeilenweise eingelesen, dann wird text auf #keywords durchsucht. ich gehe den text durch, wenn ich einen '#' finde, speichere ich seinen index, dann wird nach dem Stop-Zeichen gesucht. Es kann ein Leerzeichen, Semikolon usw sein. Falls ich beides gefunden habe, füge ich das Keyword einer List hinzu. Dann werden die Zeilen und ggf.#keyword in eine andere CSV -Datei geschrieben.
Mein Suchalgorithmus funktioniert separat sehr gut, jedoch hier gibt es Probleme. Wenn ich den Code auf meinen Datensatz anwende, werden manche #keywords nicht ganz gefunden, die werden also abgeschnitten. zb ##LoveTrumpsHate wird als #Lov geschrieben.Ich habe versucht den Fehler zu analysieren und habe keinen Zusammenhang gefunden. Es passiert irwie willkürlich.
PS Danke für den Hinweis (regular Expressions). ich probiere es noch mal umzuschreiben.
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 10:01
von nezzcarth
Leny hat geschrieben:
PS Danke für den Hinweis (regular Expressions). ich probiere es noch mal umzuschreiben.
Das solltest du wirklich in Erwägung ziehen. Denn dein jetziges Vorgehen entspricht nicht dem für Python üblichen. Das Jonglieren mit Indizes, Zustandsflags, ewig lange Ketten von Disjunktionen usw. sollte man nach Möglichkeit vermeiden -- dass du Probleme hast, den Fehler in deinem Algorithmus zu finden, zeigt einen Grund dafür auf. Mit regulären Ausdrücken lässt sich das in wenigen, überschaubaren Zeilen lösen.
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 11:03
von Melewo
Habe es einmal ausprobiert und Deine beiden Zeilen in einer CSV-Datei gespeichert.
Nur wie ich da als Flag einen Modifikator setzen kann, habe ich beim kleinen Test nicht verstanden.
Code: Alles auswählen
import re
def durchsuche_csv(file):
regex = re.compile("#[A-Za-z]+")
inhalt = open(file, "r")
suche = inhalt.read()
inhalt.close
return regex.findall(suche)
funde = durchsuche_csv("test.csv")
print("#Ausgabe:\n")
for alle in funde:
print(alle)
#Ausgabe:
#Polls
#slipping
#Debates
#MaryBrigidMcManamon
#Cruz
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 12:32
von Melewo
So, das mit dem Modifikator habe ich zwischenzeitlich noch gefunden. Zuerst hatte ich nur ein I notiert und damit gab es einen NameError. Doch so funktioniert es nun halt auch.
Nur wie man den Code in Python-Codebox-Tags setzt, ohne sich die Tags zu kopieren, habe ich noch nicht verstanden.
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 12:49
von BlackJack
@Melewo: Da ist über dem Texteingabefeld ein Auswahlfeld „Code auswählen“. Damit setzt man Codebox-Tags.
Ich würde der Lesbarkeit wegen ja `re.IGNORECASE` verwenden statt nur `re.I`. Und [a-z] dürfte nicht alle Hashtags erfassen, denn die können beispielsweise auch Umlaute enthalten. Auf der anderen Seite ist in 'foo#bar' das '#bar' *kein* Hashtag, würde aber von dem regulären Ausdruck erfasst werden.
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 13:59
von Leny
Das ist meine erste Begegnung mit Python und gleich (aus Anfängersicht) so eine schwierige Aufgabe wie Datensortierung-/bereinigung
@nezzcarth: das Problem ist es, dass der Fehler nicht in dem Suchalgorithmus ist, sondern, denke ich, etwas mir der Kodierung nicht stimmt. Das Suchalgorithmus findet alles in meinem Teststring.
@Melewo: Vielen Dank. Ich probiere es noch mal mit dem regular Expression umzuschreiben.
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 14:26
von Melewo
@BlackJack: Jetzt habe ich "Code auswählen" gefunden, war ich blind, hatte schon einmal danach gesucht.
Das mit foo#bar, gut, das könnte so wie es ist ein Problem werden. Mit Umlauten habe ich ebenfalls ein Problem, wie ich gerade sah. Werde ich noch einmal testen müssen, da half bisher weder \w noch [a-zäöüß], obwohl ich beide Dateien nach UTF-8 konvertiert und gespeichert hatte.
@Leny: Mit regulären Ausdrücken haben selbst einige gestandene Programmierer ihre Probleme. Das Wichtigste findest Du wohl unter:
https://docs.python.org/3/library/re.html
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 14:28
von Leny
Hallo,
vielen vielen Dank für eure Hilfe. Es funktioniert jetzt einwandfrei und mit weniger Code. Ich poste hier noch mal des Gesamtergebnis. Vielleicht wird es einem oder anderem weiterhelfen.
Code: Alles auswählen
import csv
import re
#Suche nach den #Keyword mit RE
def durchsuche_csv(String):
regex = re.compile("#[A-Za-z]+", re.I)
return regex.findall(String)
# öffnen der Dateien fürs Lesen und Schreiben
with open('new.csv', 'wb') as newcsv:
csvfile = open("american-election-tweets2.csv", "rb")
reader = csv.DictReader(csvfile.read().decode('utf-8-sig').encode('utf-8').splitlines(), delimiter=';')
fieldnames = ['handle', 'text', 'is_retweet', 'original_author', 'time', 'in_reply_to_screen_name',
'retweet_count', 'favorite_count', 'hashtag']
writer = csv.DictWriter(newcsv, fieldnames=fieldnames, delimiter=';')
writer.writeheader()
#Durchlaufen jede eingelesene Zeile; die Suchfunktion aufrufen und text durchsuchen
for row in reader:
keywords= durchsuche_csv(row['text'])
lowercaseKeywords=[]
#jedes gefundene #Keyword wird klein geschrieben
for word in keywords:
lowercaseKeywords.append(word.lower())
writer.writerow({'handle': row['handle'], 'text': row['text'], 'is_retweet': row['is_retweet'],
'original_author': row['original_author'],
'time': row['time'], 'in_reply_to_screen_name': row['in_reply_to_screen_name'],
'retweet_count': row['retweet_count'],
'favorite_count': row['favorite_count'], 'hashtag': lowercaseKeywords})
lowercaseKeywords = []
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 14:29
von Leny
@Melewo die Umlaute dürfen bei mir kein Problem sein, da ich einen Datensatz auf Englisch habe. Trotzdem Danke für den Hinweis
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 14:55
von Sirius3
@Leny: warum öffnest Du die Datei zum Schreiben mit `with`, die Datei zum Lesen aber nicht? Was soll dieses komplizierte Umkodieren? Die Zuweisung von `lowercaseKeywords` in der letzten Zeile ist überflüssig.
Code: Alles auswählen
import csv
import re
FIELDNAMES = ['handle', 'text', 'is_retweet', 'original_author', 'time', 'in_reply_to_screen_name', 'retweet_count', 'favorite_count', 'hashtag']
find_hashtags =re.compile("#[A-Za-z]+").findall
with open('american-election-tweets2.csv', encoding="utf-8-sig") as csvfile:
with open('new.csv', 'w', encoding="utf-8") as newcsv:
reader = csv.DictReader(csvfile, delimiter=';')
writer = csv.DictWriter(newcsv, fieldnames=FIELDNAMES, delimiter=';')
writer.writeheader()
for row in reader:
row['hashtag'] = list(map(str.lower, find_hashtags(row['text'])))
writer.writerow(row)
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 15:22
von BlackJack
@Leny: Umlaute sind in englischsprachigen Tweets vielleicht unwahrscheinlicher, aber nicht ausgeschlossen. Genau so wenig wie französische Accents, und spanische Besonderheiten, oder auch alles mögliche andere was so an Zeichen vorkommen kann. Das sollte heute auch alles kein so grosses Problem mehr sein Text auch tatsächlich als Text zu behandeln, und nicht als Bytes die ASCII enthalten. Python hat einen `unicode`-Datentyp. Den sollte man verwenden wenn man mit Text arbeitet. Insbesondere wenn der aus dem Netz kommt und UTF-8 kodiert vorliegt. ``text.strip('\xe2\x80\xa6')`` macht mit Bytes zum Beispiel ziemlich sicher nicht das was Du denkst was es macht. Das entfernt nicht nur … sondern auch einiges anderes und kann auch Bytes hinterlassen die dann kein gültiges UTF-8 mehr sind. Womit Du Dir in solchen Fällen die Daten kaputt machst.
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 15:35
von Leny
@Sirius3: wie gesagt, das ist mein erster Code in Python. Ich habe daher so Beispiele im Netz gesucht und angepasst. ich weiß nicht so genau was für Unterschiede es gibt, wenn man mit "with" oder ohne arbeitet.
@BlackJack: wie kann ich denn das row['text'] in Unicode Objekt umwandeln? Kann ich dann das Unicode Objekt genau so mit dem regulären Ausdrück durchsuchen? Ich hatte bei Einlesen viele Probleme mit Kodierung. Ich habe es probiert so zu lösen reader = csv.DictReader(csvfile.read().decode('utf-8-sig').encode('utf-8').splitlines()
das hat soweit funktioniert.
Nun werden bei wieder schreiben in die new.csv Datei komische Zeichen dazu geschrieben und die kann ich nicht los werden.
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 16:05
von Melewo
@Leny: Was ich noch übersehen und vergessen hatte, bei A-Z würde die 2016 von #Debates2016 nicht erkannt. Nehme \w oder zusätzlich noch in der Zeichenklasse noch 0-9, wenn Zahlen eine Rolle spielen. Bin zwischenzeitlich bei
Code: Alles auswählen
regex = re.compile("\B#\w+")
inhalt = open(file, "r", encoding="utf-8")
angekommen und nun wird kein "foo#bar" mehr mit eingelesen, dafür aber die Umlaute richtig.
Re: ein Teilstring finden
Verfasst: Samstag 27. Mai 2017, 19:33
von Leny
@Melewo: Danke für den Hinweis. Es ist mir gar nicht aufgefallen.