2012-01-19 21 views
48

¿Existe una función para contar la cantidad de palabras en una cadena? por ejemplo¿Cuenta el número de palabras en una cadena en R?

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

para devolver un resultado de 7

Gracias.

+0

Según la respuesta de @ Martin a continuación, creé una función [countwordpersentence.R] (https://gist.github.com/paul4forest/986a2c2fa05c3c06158e) que cuenta el número de palabras por oración en una cadena de texto dada. Para un texto largo que contiene varias oraciones, contará palabras en todas ellas y dará como resultado el número medio de palabras por oración y el número total de palabras. –

+0

str_count (temp $ question1, "") +1 sería fácil si sabes que cada palabra está separada por espacio. Está en la biblioteca stringr. –

Respuesta

55

utilizar el símbolo de expresión regular \\W para que coincida con los caracteres no de palabras, utilizando + para indicar uno o más en una fila, junto con gregexpr para encontrar todos los partidos en una cadena. Las palabras son el número de separadores de palabras, más 1.

sapply(gregexpr("\\W+", str1), length) + 1 

Este fallará con cadenas en blanco al principio o al final del vector de caracteres, cuando una "palabra" no satisface \\W 's noción de no-palabra (uno podría trabajar con otras expresiones regulares, \\S+, [[:alpha:]], etc., pero siempre habrá casos límite con un enfoque de expresiones regulares), etc. Es probable que sea más eficiente que las soluciones strsplit, que asignarán memoria para cada palabra. Las expresiones regulares se describen en ?regex.

actualización Como se señaló en los comentarios y en una respuesta diferente por @Andri el enfoque falla con (cero) y las cadenas de una sola palabra, y con arrastrarse puntuacion

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

Muchas de las otras respuestas también fallar en estos casos o casos similares (por ejemplo, espacios múltiples). Creo que la advertencia de mi respuesta sobre "noción de una palabra" en la respuesta original cubre problemas de puntuación (solución: elija una expresión regular diferente, por ejemplo, [[:space:]]+), pero los casos de cero y una palabra son un problema; La solución de @ Andri no distingue entre cero y una palabra. Por lo que tomar un enfoque 'positivo' a la búsqueda de palabras se podría

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

que lleva a

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

Una vez más la expresión regular puede ser refinado para diferentes nociones de 'palabra'.

Me gusta el uso de gregexpr() porque es eficiente desde el punto de vista de la memoria. Una alternativa usando strsplit() (como @ user813966, pero con una expresión regular para delimitar palabras) y haciendo uso de la idea original de las palabras que delimitan es

> vapply(strsplit(str1, "\\W+"), length, integer(1)) 
[1] 0 1 2 2 3 

Esto tiene que asignar memoria nueva por cada palabra que se crea, y para la lista de palabras intermedia. Esto podría ser relativamente costoso cuando los datos son "grandes", pero probablemente sea efectivo y comprensible para la mayoría de los propósitos.

+0

simple y elegante. Excelente, gracias. – John

+0

'str1 <- c ('s sss ss'," asdf asd hola esta es tu vida! "); sapply (gregexpr ("\\ W +", str1), length) + 1' devuelve '4' y' 8'. Primero correcto, segundo uno muchos más. Creo que está contando la puntuación. – fsmart

+0

Creo que está contando la puntuación al final de la oración. Bastante seguro de que le gustaría decirle a Regex que ignore las partidas de inicio y final (lo siento, no es bueno con eso o lo arreglaría yo mismo). – fsmart

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

El gsub(' {2,}',' ',str1) hace que todas las palabras se separan por un solo espacio, mediante la sustitución de todas las apariciones de dos o más espacios con un solo espacio.

El strsplit(str,' ') divide la oración en cada espacio y devuelve el resultado en una lista. El [[1]] toma el vector de palabras de esa lista. El length cuenta cuántas palabras.

> 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 
+3

Buen punto, actualizaré mi respuesta para convertir ''{2,}'' a ''''. –

+0

¿Qué pasa con las pestañas, líneas nuevas o espacios no rompibles? – bartektartanus

+0

¡Forma de resucitar una respuesta anterior de 5 años! Use '\ s' (en R, '\\ s') para incluir cualquier tipo de espacio en blanco en lugar de ''. –

11

Puede usar str_match_all, con una expresión regular que identificaría sus palabras. Lo siguiente funciona con espacios iniciales, finales y duplicados.

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]]) 
3

Puede utilizar strsplit y sapply funciones

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

¿Qué hay de los espacios dobles? – Dason

4

La solución 7 no da el resultado correcto en el caso de que haya una sola palabra. Usted no sólo debe contar con los elementos en el resultado de gregexpr (que es -1 si no, donde no partidos), pero contar con los elementos> 0.

Ergo:

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

Esto todavía tendrá problemas si 'str1' comienza o termina con caracteres que no sean palabras. Si eso es una preocupación, esta versión solo buscará espacios entre palabras: 'sapply (gregexpr (" \\ b \\ W + \\ b ", str, perl = TRUE), función (x) sum (x> 0)) + 1' –

10

Pruebe esta función desde stringi paquete

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 es una buena funcionalidad! – John

+5

Gracias :) ¡Comprueba el resto de funciones de este paquete! Estoy seguro de que encontrarás algo interesante :) ¡Todos los comentarios son bienvenidos! – bartektartanus

5

Prueba este

length(unlist(strsplit(str1," "))) 
26

manera más sencilla sería:

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

... contando todas las secuencias de caracteres no espaciales (\\S+).

Pero, ¿qué tal un poco de la función que nos permite también decidimos qué tipo de palabras nos gustaría contar y los que obras de vectores enteros así?

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 
+0

Esta función es muy rápida y se aplica sobre vectores. No puedo pedir más – timothyjgraham

+0

Esto debería ser la mejor práctica – geotheory

+0

¡Esto es simplemente lo mejor para mí! ¡maravillosa solución! –

0

Uso nchar

si vector de cadenas se llama x

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

Estudia número de espacios a continuación, añadir una

6

Puede eliminar espacios dobles y contar el número de " " en la cadena para obtener el conteo de palabras.Uso stringr y rm_white {qdapRegex}

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

Puede utilizar wc función en la biblioteca qdap:

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

utilizo la función str_count de la biblioteca stringr con el escape secuencia \w que representa:

cualquier carácter 'palabra' (letra, dígito o guión bajo en la corriente local: en el modo UTF-8 sólo se consideran letras ASCII y dígitos)

Ejemplo:

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

De las otras 9 respuestas que pude probar, solo dos (por Vincent Zoonekynd y por petermeissner) funcionaron para todas las entradas presentadas hasta ahora, pero también requieren stringr.

Pero solo esta solución funciona con todas las entradas presentadas hasta el momento, más entradas como "foo+bar+baz~spam+eggs" o .

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)) 

Salida:

6 10 10 8 9 9 7 6 6 11 
0

require (stringr) str_count (x, "\ w +") # va a estar bien con espacios dobles/triples entre palabras

Todas las otras respuestas tienen problemas con más de un espacio entre las palabras.

Cuestiones relacionadas