Zählen Sie die Anzahl aller Wörter in einer Zeichenfolge


81

Gibt es eine Funktion zum Zählen der Anzahl von Wörtern in einer Zeichenfolge? Zum Beispiel:

str1 <- "How many words are in this sentence"

um ein Ergebnis von 7 zurückzugeben.


Basierend auf der Antwort von @ Martin unten habe ich eine Funktion countwordpersentence.R erstellt, die die Anzahl der Wörter pro Satz in einer bestimmten Textzeichenfolge zählt. Bei einem langen Text mit mehreren Sätzen werden die Wörter in allen Sätzen gezählt und die mittlere Anzahl der Wörter pro Satz und die Gesamtzahl der Wörter ausgegeben.
Paul Rougieux

1
str_count (temp $ question1, "") +1 wäre einfach, wenn Sie wissen, dass jedes Wort durch ein Leerzeichen getrennt ist. Es befindet sich unter der Bibliothek stringr.
Vivek Srivastava

Antworten:


22

Sie können strsplitund sapplyFunktionen verwenden

sapply(strsplit(str1, " "), length)

Nur ein Update, dass Sie jetzt die etwas neue lengthsFunktion in Basis R verwenden können, die die Länge jedes Elements findet:lengths(strsplot(str, " "))
Nick Tierney

Das ist sehr gut. Das Problem ist, wenn Sie so etwas wie "Wort, Wort, Wort" haben. In diesem Fall wird 1
Dimitrios Zacharatos

71

Verwenden Sie das Symbol \\Wfür reguläre Ausdrücke , um Nicht-Wort-Zeichen abzugleichen +, und geben Sie ein oder mehrere Zeichen in einer Reihe an gregexpr, um alle Übereinstimmungen in einer Zeichenfolge zu finden. Wörter sind die Anzahl der Worttrennzeichen plus 1.

lengths(gregexpr("\\W+", str1)) + 1

Dies wird mit leeren Saiten am Anfang oder Ende des Zeichenvektor scheitern, wenn ein „Wort“ nicht erfüllt \\W‚s Begriff des Nicht-Wortes (man könnte mit anderen regulären Ausdrücken arbeiten, \\S+, [[:alpha:]]etc., aber es wird immer Dies sind wahrscheinlich effizientere strsplitLösungen als Lösungen, bei denen jedem Wort Speicher zugewiesen wird. Reguläre Ausdrücke sind in beschrieben ?regex.

Aktualisieren Wie in den Kommentaren und in einer anderen Antwort von @Andri erwähnt, schlägt der Ansatz mit (Null-) und Ein-Wort-Zeichenfolgen sowie mit nachgestellten Satzzeichen fehl

str1 = c("", "x", "x y", "x y!" , "x y! z")
lengths(gregexpr("[A-z]\\W+", str1)) + 1L
# [1] 2 2 2 3 3

Viele der anderen Antworten schlagen auch in diesen oder ähnlichen Fällen (z. B. mehreren Leerzeichen) fehl. Ich denke, die Einschränkung meiner Antwort bezüglich der Vorstellung eines Wortes in der ursprünglichen Antwort deckt Probleme mit der Interpunktion ab (Lösung: Wählen Sie einen anderen regulären Ausdruck, z. B. [[:space:]]+), aber die Fälle mit null und einem Wort sind ein Problem. @ Andris Lösung unterscheidet nicht zwischen null und einem Wort. Ein "positiver" Ansatz, um Wörter zu finden, könnte man also

sapply(gregexpr("[[:alpha:]]+", str1), function(x) sum(x > 0))

Führen zu

sapply(gregexpr("[[:alpha:]]+", str1), function(x) sum(x > 0))
# [1] 0 1 2 2 3

Wieder könnte der reguläre Ausdruck für verschiedene Begriffe von "Wort" verfeinert werden.

Ich mag die Verwendung von, gregexpr()weil es speichereffizient ist. Eine alternative Verwendung strsplit()(wie @ user813966, jedoch mit einem regulären Ausdruck zum Abgrenzen von Wörtern) und Verwenden des ursprünglichen Begriffs der Abgrenzung von Wörtern ist

lengths(strsplit(str1, "\\W+"))
# [1] 0 1 2 2 3

Dies muss für jedes erstellte Wort und für die Zwischenliste der Wörter einen neuen Speicher zuweisen. Dies kann relativ teuer sein, wenn die Daten "groß" sind, aber wahrscheinlich ist es für die meisten Zwecke effektiv und verständlich.


str1 <- c('s ss sss ss', "asdf asd hello this is your life!"); sapply(gregexpr("\\W+", str1), length) + 1gibt zurück 4und 8. Erstens richtig, zweitens zu viele. Ich denke, es zählt die Interpunktion.
Francis Smart

Ich denke, es zählt die Interpunktion am Ende des Satzes. Ich bin mir ziemlich sicher, dass Sie Regex anweisen möchten, Start- und Endspiele zu ignorieren (sorry, nicht gut damit, oder ich würde es selbst reparieren).
Francis Smart

sapply(gregexpr("\\W+", "word"), length) + 1gibt 2
jaycode

Danke @fsmart - Ich denke, die Besorgnis über Interpunktion wird durch den Haftungsausschluss über den Begriff des Nichtworts in der ursprünglichen Antwort abgedeckt. Ich habe die Antwort aktualisiert.
Martin Morgan

Dank @jaycode ist die Unfähigkeit, 1 (oder Null) Worteingaben zu zählen, ein Problem. Ich habe die ursprüngliche Antwort aktualisiert.
Martin Morgan

47

Der einfachste Weg wäre:

require(stringr)
str_count("one,   two three 4,,,, 5 6", "\\S+")

... alle Sequenzen auf Nicht-Leerzeichen zählen ( \\S+).

Aber was ist mit einer kleinen Funktion, mit der wir auch entscheiden können, welche Art von Wörtern wir zählen möchten und welche auch für ganze Vektoren funktioniert ?

require(stringr)
nwords <- function(string, pseudo=F){
  ifelse( pseudo, 
          pattern <- "\\S+", 
          pattern <- "[[:alpha:]]+" 
        )
  str_count(string, pattern)
}

nwords("one,   two three 4,,,, 5 6")
# 3

nwords("one,   two three 4,,,, 5 6", pseudo=T)
# 6

34

Ich benutze die str_countFunktion aus der stringrBibliothek mit der Escape-Sequenz \w, die darstellt:

Beliebiges 'Wort'-Zeichen (Buchstabe, Ziffer oder Unterstrich im aktuellen Gebietsschema: Im UTF-8-Modus werden nur ASCII-Buchstaben und -Ziffern berücksichtigt).

Beispiel:

> str_count("How many words are in this sentence", '\\w+')
[1] 7

Von allen anderen 9 Antworten, die ich testen konnte, arbeiteten nur zwei (von Vincent Zoonekynd und von Petermeissner) für alle hier vorgestellten Eingaben, aber sie erfordern auch stringr.

Aber nur diese Lösung funktioniert mit allen bisher präsentierten Eingaben sowie Eingaben wie "foo+bar+baz~spam+eggs"oder "Combien de mots sont dans cette phrase ?".

Benchmark:

library(stringr)

questions <-
  c(
    "", "x", "x y", "x y!", "x y! z",
    "foo+bar+baz~spam+eggs",
    "one,   two three 4,,,, 5 6",
    "How many words are in this sentence",
    "How  many words    are in this   sentence",
    "Combien de mots sont dans cette phrase ?",
    "
    Day after day, day after day,
    We stuck, nor breath nor motion;
    "
  )

answers <- c(0, 1, 2, 2, 3, 5, 6, 7, 7, 7, 12)

score <- function(f) sum(unlist(lapply(questions, f)) == answers)

funs <-
  c(
    function(s) sapply(gregexpr("\\W+", s), length) + 1,
    function(s) sapply(gregexpr("[[:alpha:]]+", s), function(x) sum(x > 0)),
    function(s) vapply(strsplit(s, "\\W+"), length, integer(1)),
    function(s) length(strsplit(gsub(' {2,}', ' ', s), ' ')[[1]]),
    function(s) length(str_match_all(s, "\\S+")[[1]]),
    function(s) str_count(s, "\\S+"),
    function(s) sapply(gregexpr("\\W+", s), function(x) sum(x > 0)) + 1,
    function(s) length(unlist(strsplit(s," "))),
    function(s) sapply(strsplit(s, " "), length),
    function(s) str_count(s, '\\w+')
  )

unlist(lapply(funs, score))

Ausgabe:

6 10 10  8  9  9  7  6  6 11

Dieser Ansatz ist ausgezeichnet, aber ein Problem, auf das ich immer noch stoße, ist, dass Wörter, die einen Apostroph enthalten (z. B. "Ich" oder "Johns"), doppelt gezählt werden. Gibt es eine Möglichkeit, dies anzugehen?
Thredolsen

2
@Thredolsen Wenn Sie sicher sind, dass es keine Apostrophe gibt, die als Worttrennzeichen behandelt werden sollen, können Sie eine Zeichenklasse verwenden '[\\w\']+'(kann sie nicht testen, daher kann xkcd.com/1638 zutreffen), andernfalls bin ich mir nicht sicher, ob Regex ist mächtig genug, um es im allgemeinen Fall zu behandeln :)
Arekolek

1
Ich bin mir nicht sicher, ob dies eine gute Annahme ist, aber wenn nach dem Apostroph immer nur ein oder zwei Buchstaben stehen, '\\w+(\'\\w{1,2})?'könnte dies eine gute Lösung sein.
Arekolek

Vielen Dank. Beide Ansätze funktionieren größtenteils, aber '[\\ w \'] + 'scheint in meinem Fall besser zu sein, da einige Wörter nach einem Apostroph mehr als 2 Zeichen enthalten (z. B. Uhr). Verwandte Folgefrage: Gibt es eine Möglichkeit, auch Fälle auszuschließen, in denen auf einen Doppelpunkt direkt ein numerisches Zeichen folgt (z. B. '10: 15 'als ein Wort anstatt als zwei)?
Thredolsen

2
In diesem Kommentar werde ich die einfache Regex-Syntax verwenden, sodass Beispiele einige zusätzliche Backslashes benötigen. Um Wörter wie o'clockund friggin'Sie könnten es abdecken \w+('\w*)?(ich weiß nicht, ob es Wörter gibt, die mit Apostroph beginnen?). Um zusätzlich mit Stunden umzugehen, können Sie versuchen, sie \d?\d:\d\d|\w+('\w*)?anzupassen oder etwas noch komplizierteres zu tun, je nach Ihren Bedürfnissen. Aber hier geht es immer weniger um R und mehr darum, wie Sie ein Wort definieren. Vielleicht können Sie also eine separate Frage stellen, um Ihre spezifischen Bedürfnisse abzudecken?
Arekolek

15
str2 <- gsub(' {2,}',' ',str1)
length(strsplit(str2,' ')[[1]])

Die gsub(' {2,}',' ',str1)stellt sicher , dass alle Worte nur durch ein Leerzeichen getrennt, durch alle Vorkommen von zwei Ersatz oder mehr Räumen mit einem Raum.

Das strsplit(str,' ')teilt den Satz an jeder Stelle auf und gibt das Ergebnis in einer Liste zurück. Der [[1]]greift nach dem Wortvektor aus dieser Liste. Das lengthzählt wie viele Wörter.

> str1 <- "How many words are in this     sentence"
> str2 <- gsub(' {2,}',' ',str1)
> str2
[1] "How many words are in this sentence"
> strsplit(str2,' ')
[[1]]
[1] "How"      "many"     "words"    "are"      "in"       "this"     "sentence"
> strsplit(str2,' ')[[1]]
[1] "How"      "many"     "words"    "are"      "in"       "this"     "sentence"
> length(strsplit(str2,' ')[[1]])
[1] 7

Was ist mit Tabulatoren, neuen Zeilen oder nicht unterbrechbaren Leerzeichen?
Bartektartanus

Weg, um eine 5 Jahre alte Antwort wiederzubeleben! Verwenden Sie '\ s' (in R '\\ s'), um eine beliebige Art von Leerzeichen anstelle von '' einzuschließen.
mathematisch.Kaffee

Ich habe eine Benachrichtigung über meine Antwort erhalten und andere angeschaut, um sie leicht zu verbessern: D Sei nicht böse! :) PS. Ich mag Mathe und Kaffee auch!
Bartektartanus

13

Sie können str_match_alleinen regulären Ausdruck verwenden, der Ihre Wörter identifiziert. Das Folgende funktioniert mit anfänglichen, endgültigen und duplizierten Leerzeichen.

library(stringr)
s <-  "
  Day after day, day after day,
  We stuck, nor breath nor motion;
"
m <- str_match_all( s, "\\S+" )  # Sequences of non-spaces
length(m[[1]])

11

Versuchen Sie diese Funktion aus dem stringiPaket

   require(stringi)
   > s <- c("Lorem ipsum dolor sit amet, consectetur adipisicing elit.",
    +        "nibh augue, suscipit a, scelerisque sed, lacinia in, mi.",
    +        "Cras vel lorem. Etiam pellentesque aliquet tellus.",
    +        "")
    > stri_stats_latex(s)
        CharsWord CharsCmdEnvir    CharsWhite         Words          Cmds        Envirs 
              133             0            30            24             0             0 

6
@bartektartanusthat ist einige nette Funktionalität!
John

5
Vielen Dank :) Überprüfen Sie den Rest der Funktionen aus diesem Paket! Ich bin sicher, Sie werden etwas Interessantes finden :) Kommentare sind willkommen!
Bartektartanus

7

Sie können die wc- Funktion in der Bibliothek qdap verwenden :

> str1 <- "How many words are in this sentence"
> wc(str1)
[1] 7

6

Sie können doppelte Leerzeichen entfernen und die Anzahl " "der Zeichen in der Zeichenfolge zählen, um die Anzahl der Wörter zu ermitteln. Verwenden Sie stringr und rm_white{ qdapRegex }

str_count(rm_white(s), " ") +1


5

Ebenfalls ab stringiPaket die unkomplizierte Funktionstri_count_words

stringi::stri_count_words(str1)
#[1] 7

4

Die Lösung 7 liefert nicht das richtige Ergebnis, wenn nur ein Wort vorhanden ist. Sie sollten nicht nur die Elemente im Ergebnis von gregexpr zählen (was -1 ist, wenn es keine Übereinstimmungen gibt), sondern auch die Elemente> 0 zählen.

Ergo:

sapply(gregexpr("\\W+", str1), function(x) sum(x>0) ) + 1 

Dies hat immer noch Probleme, wenn es str1mit Nicht-Wort-Zeichen beginnt oder endet. Wenn das ein Problem ist, wird diese Version nur nach Leerzeichen zwischen Wörtern suchen:sapply(gregexpr("\\b\\W+\\b", str, perl=TRUE), function(x) sum(x>0) ) + 1
Adam Bradley

4
require(stringr)
str_count(x,"\\w+")

wird gut mit doppelten / dreifachen Leerzeichen zwischen Wörtern

Alle anderen Antworten haben Probleme mit mehr als einem Leerzeichen zwischen den Wörtern.


2

erfordern (stringr)

Definieren Sie eine sehr einfache Funktion

str_words <- function(sentence) {

  str_count(sentence, " ") + 1

}

Prüfen

str_words(This is a sentence with six words)

1

Verwenden nchar

wenn ein Vektor von Strings aufgerufen wird x

(nchar(x) - nchar(gsub(' ','',x))) + 1

Finden Sie die Anzahl der Leerzeichen heraus und fügen Sie eines hinzu


1

Ich habe die folgende Funktion und den folgenden regulären Ausdruck für die Anzahl der Wörter nützlich gefunden, insbesondere bei einfachen oder doppelten Bindestrichen, bei denen erstere im Allgemeinen nicht als Wortumbruch gelten sollten, z. B. bekannte HiFi-Dateien. wohingegen ein doppelter Bindestrich ein Interpunktionsbegrenzer ist, der nicht durch Leerzeichen begrenzt ist - beispielsweise für Bemerkungen in Klammern.

txt <- "Don't you think e-mail is one word--and not two!" #10 words
words <- function(txt) { 
length(attributes(gregexpr("(\\w|\\w\\-\\w|\\w\\'\\w)+",txt)[[1]])$match.length) 
}

words(txt) #10 words

Stringi ist ein nützliches Paket. In diesem Beispiel werden jedoch Wörter aufgrund von Bindestrichen überzählt.

stringi::stri_count_words(txt) #11 words

0

Mit dem stringr- Paket kann man auch ein einfaches Skript schreiben, das einen Vektor von Strings beispielsweise durch eine for-Schleife durchlaufen kann.

Sagen wir

df $ text

enthält einen Vektor von Zeichenfolgen, die wir analysieren möchten. Zunächst fügen wir dem vorhandenen Datenrahmen df wie folgt zusätzliche Spalten hinzu:

df$strings    = as.integer(NA)
df$characters = as.integer(NA)

Dann führen wir eine for-Schleife über den Vektor der Zeichenfolgen wie folgt aus:

for (i in 1:nrow(df)) 
{
   df$strings[i]    = str_count(df$text[i], '\\S+') # counts the strings
   df$characters[i] = str_count(df$text[i])         # counts the characters & spaces
}

Die resultierenden Spalten: Zeichenfolgen und Zeichen enthalten die Anzahl der Wörter und Zeichen. Dies wird in einem Durchgang für einen Vektor von Zeichenfolgen erreicht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.