Подсчитайте количество всех слов в строке


82

Есть ли функция для подсчета количества слов в строке? Например:

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

чтобы вернуть результат 7.


Основываясь на ответе @Martin ниже, я создал функцию countwordpersentence.R, которая подсчитывает количество слов в предложении в заданной текстовой строке. Для длинного текста, содержащего несколько предложений, он будет подсчитывать слова во всех из них и выводить среднее количество слов в предложении и общее количество слов.
Поль Руже,

1
str_count (temp $ question1, "") +1 было бы легко, если бы вы знали, что каждое слово разделено пробелом. Он находится под библиотекой.
Вивек Шривастава

Ответы:


24

Вы можете использовать strsplitи sapplyфункции

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

2
Просто обновление: теперь вы можете использовать несколько новую lengthsфункцию в базе R, которая находит длину каждого элемента:lengths(strsplot(str, " "))
Ник Тирни,

это очень хорошо, проблема в том, что когда у вас есть что-то вроде «слово, слово, слово», в этом случае оно вернет 1
Димитриос Захаратос

71

Используйте символ регулярного выражения \\Wдля сопоставления несловесных символов, используя +для обозначения одного или нескольких в строке, а также gregexprдля поиска всех совпадений в строке. Слова - это количество разделителей слов плюс 1.

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

Это будет терпеть неудачу с пустыми строками в начале или в конце вектора символов, когда «слово» не удовлетворяет \\W«s понятие несловообразующего (один может работать с другими регулярными выражениями \\S+, [[:alpha:]]и т.д., но там всегда будет быть крайними случаями с подходом регулярных выражений) и т.д. Это, вероятно, более эффективно, чем strsplitрешения, которые будут выделять память для каждого слова. Регулярные выражения описаны в ?regex.

Обновление Как отмечалось в комментариях и в другом ответе @Andri, подход не работает с (нулевыми) и однословными строками и с конечной пунктуацией

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

Многие другие ответы также терпят неудачу в этих или подобных случаях (например, с несколькими пробелами). Я думаю, что предостережение моего ответа о «понятии одного слова» в исходном ответе касается проблем с пунктуацией (решение: выберите другое регулярное выражение, например,[[:space:]]+ ), но случаи с нулевым и одним словом являются проблемой; Решение @ Andri не умеет различать ноль и единицу. Таким образом, используя «позитивный» подход к поиску слов, можно

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

Ведущий к

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

Опять же, регулярное выражение может быть уточнено для различных понятий «слово».

Мне нравится использование, gregexpr()потому что оно эффективно с точки зрения памяти. Альтернативой использования strsplit()(например, @ user813966, но с регулярным выражением для разграничения слов) и использования исходного понятия разграничения слов является

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

При этом необходимо выделить новую память для каждого созданного слова и для промежуточного списка слов. Это может быть относительно дорого, когда данные «большие», но, вероятно, это эффективно и понятно для большинства целей.


str1 <- c('s ss sss ss', "asdf asd hello this is your life!"); sapply(gregexpr("\\W+", str1), length) + 1возвращается 4и 8. Первое правильно, второе - слишком много. Думаю, дело в пунктуации.
Фрэнсис Смарт

Я думаю, это счет знаков препинания в конце предложения. Совершенно уверен, что вы захотите указать регулярному выражению игнорировать начальные и конечные совпадения (извините, это не годится, или я бы исправил это сам).
Фрэнсис Смарт

sapply(gregexpr("\\W+", "word"), length) + 1возвращает 2
jaycode

Спасибо @fsmart - я думаю, что озабоченность по поводу пунктуации покрыта отказом от ответственности о «понятии не-слова» в исходном ответе. Я обновил ответ.
Мартин Морган

Спасибо @jaycode, невозможность подсчитать 1 (или ноль) ввод слов является проблемой. Я обновил исходный ответ.
Мартин Морган

49

Самый простой способ :

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

... подсчет всех последовательностей непробельных символов (\\S+ ).

Но как насчет небольшой функции, которая позволяет нам также решать, какие слова мы хотели бы подсчитать и которая также работает с целыми векторами ?

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

37

Я использую str_countфункцию из stringrбиблиотеки с escape-последовательностью, \wкоторая представляет:

любой символ "слово" (буква, цифра или подчеркивание в текущей локали: в режиме UTF-8 учитываются только буквы и цифры ASCII)

Пример:

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

Из всех 9 ответов, которые мне удалось протестировать, только два (Винсент Зоонекинд и Петермейсснер) работали для всех представленных здесь входных данных, но они также требуют stringr .

Но только это решение работает со всеми представленными на данный момент входными данными, а также такими входами, как "foo+bar+baz~spam+eggs"или"Combien de mots sont dans cette phrase ?" .

Контрольный показатель:

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

Вывод:

6 10 10  8  9  9  7  6  6 11

Это превосходный подход, но одна проблема, с которой я все еще сталкиваюсь, заключается в том, что он дважды учитывает слова, содержащие апостроф (например, «Я» или «Джона»). Есть ли способ решить эту проблему?
Thredolsen

2
@Thredolsen, если вы уверены, что не будет апострофов, которые следует рассматривать как разделители слов, вы можете использовать класс символов '[\\w\']+'(не можете проверить его, поэтому может применяться xkcd.com/1638 ), в противном случае я не уверен, что regex достаточно мощный, чтобы справиться с этим в общем случае :)
arekolek

1
Не уверен, что это хорошее предположение, но если после апострофа всегда есть только одна или две буквы, то это '\\w+(\'\\w{1,2})?'может быть хорошим решением.
arekolek

Спасибо. Оба подхода работают по большей части, но '[\\ w \'] + 'в моем случае кажется лучше, поскольку некоторые слова содержат более двух символов после апострофа (например, o'clock). Связанный дополнительный вопрос: есть ли способ также исключить случаи, когда за двоеточием непосредственно следует числовой символ (например, считать «10:15» одним словом, а не двумя)?
Thredolsen

2
В этом комментарии я собираюсь использовать простой синтаксис регулярных выражений, поэтому для примеров потребуются дополнительные обратные косые черты. Чтобы охватить такие слова, как o'clockи friggin'вы могли бы \w+('\w*)?(я не знаю, есть ли слова, начинающиеся с апострофа?). Чтобы дополнительно справиться с часами, вы можете попытаться сопоставить их, как \d?\d:\d\d|\w+('\w*)?или сделать что-то еще более сложное, в зависимости от ваших потребностей. Но это все меньше и меньше о R и больше о том, как вы определяете слово, так что, может быть, вы можете опубликовать отдельный вопрос, чтобы охватить свои конкретные потребности?
arekolek

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

В gsub(' {2,}',' ',str1) убеждается все слова разделяются только одним пробелом, путем замены всех вхождений двух или более пробелов одним пробелом.

Функция strsplit(str,' ')разбивает предложение по каждому пробелу и возвращает результат в виде списка. [[1]]Хватает вектор слов из этого списка. lengthПодсчитывает , сколько слов.

> 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

А как насчет табуляции, новых строк или неразрывных пробелов?
bartektartanus

Способ воскресить ответ пятилетней давности! Используйте '\ s' (в R, '\\ s') для включения любого типа пробелов, а не ''.
mathematical.coffee

Я получил уведомление о своем ответе и посмотрел на других, чтобы немного улучшить их: D Не сердитесь! :) PS. Я тоже люблю математику и кофе!
bartektartanus

13

Вы можете использовать str_match_all, с регулярным выражением, которое будет идентифицировать ваши слова. Следующее работает с начальным, конечным и дублированным пробелами.

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

Попробуйте эту функцию из stringiпакета

   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
@bartektartanust, это хорошая функциональность!
Джон

5
Спасибо :) Проверьте остальные функции из этого пакета! Уверен, вы найдете что-то интересное :) Любые комментарии приветствуются!
bartektartanus

7

Вы можете использовать функцию wc в библиотеке qdap :

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

6

Вы можете удалить двойные пробелы и подсчитать количество " "в строке, чтобы получить количество слов. Используйте stringr и rm_white{ qdapRegex }

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


5

Также из stringiпакета, прямая функцияstri_count_words

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

4

Решение 7 не дает правильного результата, если есть только одно слово. Вы должны не просто подсчитывать элементы в результате gregexpr (который равен -1, если там, где нет совпадений), но подсчитывать элементы> 0.

Ergo:

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

Это все равно будет иметь проблемы, если str1начинается или заканчивается символами, не являющимися словами. Если это вызывает беспокойство, эта версия будет искать только пробелы между словами:sapply(gregexpr("\\b\\W+\\b", str, perl=TRUE), function(x) sum(x>0) ) + 1
Адам Брэдли

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

будет нормально с двойными / тройными пробелами между словами

Во всех других ответах есть проблемы с более чем одним пробелом между словами.


2

требовать (строка)

Определите очень простую функцию

str_words <- function(sentence) {

  str_count(sentence, " ") + 1

}

Проверьте

str_words(This is a sentence with six words)

1

Использовать nchar

если вектор строк называется x

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

Узнайте количество пробелов и добавьте один


1

Я нашел следующую функцию и регулярное выражение, полезные для подсчета слов, особенно при работе с одинарными и двойными дефисами, где первый обычно не должен считаться разрывом слова, например, хорошо известный, привет-Fi; тогда как двойной дефис - это разделитель знаков препинания, который не ограничен пробелом, например, для замечаний в скобках.

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 - полезный пакет. Но в этом примере слишком много слов из-за дефиса.

stringi::stri_count_words(txt) #11 words

0

Со стрингером пакета можно также написать простой скрипт, который может перемещаться по вектору строк, например, через цикл for.

Скажем

df $ text

содержит вектор строк, которые мы хотим проанализировать. Сначала мы добавляем дополнительные столбцы в существующий фрейм данных df, как показано ниже:

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

Затем мы запускаем цикл for по вектору строк, как показано ниже:

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
}

Результирующие столбцы: строки и символ будут содержать количество слов и символов, и это будет достигнуто за один раз для вектора строк.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.