ein Teilstring finden

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
Leny
User
Beiträge: 16
Registriert: Freitag 26. Mai 2017, 19:34

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
Zuletzt geändert von Anonymous am Samstag 27. Mai 2017, 11:43, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@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.
Leny
User
Beiträge: 16
Registriert: Freitag 26. Mai 2017, 19:34

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.
Zuletzt geändert von Anonymous am Samstag 27. Mai 2017, 11:46, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

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.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

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
Zuletzt geändert von Anonymous am Samstag 27. Mai 2017, 11:52, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

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.

Code: Alles auswählen

regex = re.compile("#[a-z]+", re.I)
Nur wie man den Code in Python-Codebox-Tags setzt, ohne sich die Tags zu kopieren, habe ich noch nicht verstanden.
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.
Leny
User
Beiträge: 16
Registriert: Freitag 26. Mai 2017, 19:34

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.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

@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
Leny
User
Beiträge: 16
Registriert: Freitag 26. Mai 2017, 19:34

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 = []
Zuletzt geändert von Anonymous am Samstag 27. Mai 2017, 15:09, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Leny
User
Beiträge: 16
Registriert: Freitag 26. Mai 2017, 19:34

@Melewo die Umlaute dürfen bei mir kein Problem sein, da ich einen Datensatz auf Englisch habe. Trotzdem Danke für den Hinweis
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@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)
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.
Leny
User
Beiträge: 16
Registriert: Freitag 26. Mai 2017, 19:34

@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.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

@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.
Leny
User
Beiträge: 16
Registriert: Freitag 26. Mai 2017, 19:34

@Melewo: Danke für den Hinweis. Es ist mir gar nicht aufgefallen.
Antworten