Anzahl von Wörtern in String zählen

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
SpyHRO65
User
Beiträge: 8
Registriert: Montag 22. April 2013, 15:59

Kann mir jemand sagen wie ich die anzahl von Wörtern in einem String zählen kann?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo SpyHRO65,

was weißt Du über Strings, z.B. wie man Strings in Wörter ausspaltet?
Falls nicht, nimm das Anfängertutorium Deiner Wahl und lese nach, was "split" macht.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Ich weiss, man sollte nicht immer fertigen Lösungen liefern...
Folgendes habe ich mal über eine 40GB Passwortliste laufen lassen um zu sehen, wieviel Wörter da drin sind..

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import  sys

fileName = "Dein String, Deine Textdatei"

num_lines = 0
num_words = 0
num_chars = 0

with open(fileName, 'r') as f:
    for line in f:
        words = line.split()

        num_lines += 1
        num_words += len(words)
        num_chars += len(line)

print "Anzahl Zeilen: ", num_lines
print "Anzahl Wörter: ", num_words
print "Anzahl Buchstaben: ", num_chars
EDIT:

Oder falls die einzelnen Wörter gezählt werden sollen:

Code: Alles auswählen

from collections import Counter

with open("test.txt") as f:
    counts = Counter(f.read().split())
    print counts
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich biete noch das:

Code: Alles auswählen

import re
s = " Hallo Welt, das ist ein  Test! "
sum(1 for space in re.finditer(r"[^\s]+", s))
> 6
Könnte schneller sein, als die Variante mit ``split``, da keine Liste erstellt werden muss. Aber lesbarer ist natürlich die anderen. Müsste man glatt mal testen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hyperion: die inverse Menge zu »\s« ist »\S«. Und die Variante über reguläre Ausdrücke ist rund 6mal langsamer.

Code: Alles auswählen

re.sub(r'\w+', 'x', text).count('x')
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sirius3 hat geschrieben:Und die Variante über reguläre Ausdrücke ist rund 6mal langsamer.
Ah sieh an... hätte ich nicht gedacht. (Ich nehme an Du meintest meine Variante?) Wie sieht es denn mit Deiner aus?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
JohnDoe

Ich hab das mal mit einer Logdatei (2,1MB) mit jeweils 100 durchgängen (ohne Interpreterstart oder Imports) getestet und die Zeit mit dem Tool "time" gemessen:

Code: Alles auswählen

import re
for x in range(0,100):
    with open ('test.txt', 'r') as f:
        print(sum(1 for space in re.finditer(r"[\S]+", f.read())))
Dauer: 58s

Code: Alles auswählen

import re
for x in range(0,100):
    with open ('test.txt', 'r') as f:
        print(sum(1 for space in re.finditer(r"[^\s]+", f.read())))
Dauer: 61s

Code: Alles auswählen

from collections import Counter
for x in range(0,100):
    with open('test.txt') as f:
        counts = Counter(f.read().split())
        print(counts)
Dauer ohne Textausgabe: 1m 7s
Dauer mit Textausgabe: 2m 22s

Code: Alles auswählen

for x in range(0,100):
    with open('test.txt', 'r') as f:
        print(len(f.read().split()))
Dauer: 11s

Daraus schließe ich 3 Dinge:
a) Immer zuerst das Einfachste probieren (KISS)
b) Keinesfalls verfrüht optimieren (oder einfach gar nicht, funktioniert auch so wunderbar)
c) Ich sollte mir andere Hobbies suchen

mfg
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Wobei hier alle Loesungen ein potentielles Problem mit richtig grossen Dateien haben. Vor allem 4, da hier zeitweise das doppelte der Dateigroesse an Speicher benoetigt wird.
JohnDoe

cofi hat geschrieben:Wobei hier alle Loesungen ein potentielles Problem mit richtig grossen Dateien haben. Vor allem 4, da hier zeitweise das doppelte der Dateigroesse an Speicher benoetigt wird.
Ich denke alle 4 von mir getesteten Implementierungen haben Probleme beim Speicherbedarf, andreseits wer hat schon Textdateien > 50MB? Das dürfte wohl eher die Ausnahme darstellen.

mfg
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Aber nur das 4. belegt zeitweise das doppelte an Speicherplatz. Wer so grosse Textdateien hat? Jemand der Log-Dateien hat, und das ist nur einer von vielen Faellen ..
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Dann halt noch die speicherschonende Variante:

Code: Alles auswählen

with open('test.txt') as f:
    print(reduce(
        lambda (s,b),c: (s+(b and b!=c.isspace()), c.isspace()),
        iter(lambda: f.read(1), ''), (0,1))[0])
mit maximal einem Zeichen im Speicher ;-)
JohnDoe

cofi hat geschrieben:Aber nur das 4. belegt zeitweise das doppelte an Speicherplatz. Wer so grosse Textdateien hat? Jemand der Log-Dateien hat, und das ist nur einer von vielen Faellen ..
Log-Dateien werden für gewöhnlich nicht größer als 10MB (Erfahrungswert), selbst auf meinen Server finde ich dank logrotate keine einzige Logdatei > 3MB.

Ein Buch mit etwa 700 Seiten dürfte in reiner Textform und UTF-8 Codierung nicht größer als 2MB sein.

Meine kleine Liste mit Passwörtern hat knapp 30000 Einträge und selbst die belegt nicht mehr als 300kB.

Ich will nicht bestreiten, dass die 4. Lösung zeitweise den doppelten Speicher belegt. Allerdings dürften nur die wenigsten Leute, die Wörter in einem Textdokument zählen wollen, Dateien > 50MB verwenden.

Was mir noch in den Sinn kommen würde sind Hashtables, die man allerdings aus verschiedenen Gründen wohl besser in eine Datenbank packt.

mfg
BlackJack

@JohnDoe: Das ist wohl ein persönlicher Erfahrungswert von Dir. Ich kenne grössere Logdateien. Und auch Textdateien mit Messungen die deutlich grösser sind. Auf der anderen Seite kenne ich auch Rechner die nicht mehrere GiB RAM haben.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

JohnDoe hat geschrieben: Meine kleine Liste mit Passwörtern hat knapp 30000 Einträge und selbst die belegt nicht mehr als 300kB.
mfg

Meine PW Liste mit 20GB

Code: Alles auswählen

Anzahl Zeilen:       4'103'549'346
Anzahl Wörter:       4'103'549'346
Anzahl Buchstaben:  24'541'533'232
Die andere Lsite mit 40MB

Code: Alles auswählen

Anzahl Zeilen:  3917193
Anzahl Wörter:  4101726
Anzahl Buchstaben:  43391014
JohnDoe

BlackJack hat geschrieben:Ich kenne grössere Logdateien. Und auch Textdateien mit Messungen die deutlich grösser sind. Auf der anderen Seite kenne ich auch Rechner die nicht mehrere GiB RAM haben.
Es geht mir nicht darum ob es Logdateien gibt die größer sind als 50MB und es geht mir auch nicht darum, ob es Rechner gibt die weniger als 1GB RAM haben. Wenn man, wie @lackschuh, eine Passwortliste mit 20GB rumschleppt, dann lohnt es sich das Programm so zu erweitern, dass es mit der Datenmenge klarkommt. Ansonsten: Optimierungen immer erst dann anwenden, wenn es nötig ist.

Mehr wollte ich nicht ausdrücken.

mfg
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier mal eine Variante, die häppchenweise lesen kann:

Code: Alles auswählen

def count_words(stream, chunk_size=1024*1024):
    num_words = 0
    saw_nonspace = False
    chunk_reader = iter(lambda: stream.read(chunk_size), '')
    for chunk in chunk_reader:
        num_chunk_words = len(chunk.split())
        if saw_nonspace and not chunk[0].isspace():
            num_chunk_words -= 1
        num_words += num_chunk_words
        saw_nonspace = not chunk[-1].isspace()
    return num_words

def test():
    from StringIO import StringIO
    s = StringIO(" as  s   s  s  ")
    print count_words(s, 2)


if __name__ == '__main__':
    test()
Antworten