计算字符串中所有单词的数量


82

有功能来计算字符串中的单词数吗?例如:

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

返回结果7。


基于下面@Martin的答案,我创建了一个功能countwordpersentence.R,它计算给定文本字符串中每个句子的单词数。对于包含几个句子的长文本,它将对所有单词进行计数,并输出每个句子的平均单词数和单词总数。
Paul Rougieux 2015年

1
如果您知道每个单词都用空格分隔,则str_count(temp $ question1,“”)+1会很容易。它在库字符串下。
Vivek Srivastava

Answers:


22

您可以使用strsplitsapply功能

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

只是一个更新,您现在可以使用lengths基础R中的某些新功能来查找每个元素的长度:lengths(strsplot(str, " "))
Nick Tierney

这非常好,问题是当您遇到诸如“单词,单词,单词”之类的东西时,它将返回1
Dimitrios Zacharatos 19/12/12

71

使用正则表达式符号\\W匹配非单词字符,+用于表示一行中的一个或多个,以及gregexpr查找字符串中的所有匹配项。单词是单词分隔符的数量加1。

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

当“单词”不满足\\W的非单词概念时(字符可以与其他正则表达式一起使用,\\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返回48。第一个正确,第二个太多。我认为它正在计算标点符号。
弗朗西斯·斯玛特

我认为它正在计算句子结尾处的标点符号。可以肯定的是,您希望告诉正则表达式忽略开始和结束匹配(对不起,不好用,否则我会自己修复)。
弗朗西斯·斯玛特

sapply(gregexpr("\\W+", "word"), length) + 1返回2
jaycode,2015年

感谢@fsmart-我认为原始答案中有关“非单词概念”的免责声明涵盖了对标点符号的关注。我已经更新了回复。
马丁·摩根

感谢@jaycode,无法计数1(或零)个单词输入是一个问题。我已经更新了原始答案。
马丁·摩根

47

最简单的方法是:

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

35

str_countstringr库中的函数与\w表示以下内容的转义序列一起使用:

任何“单词”字符(在当前语言环境中为字母,数字或下划线:在UTF-8模式下,仅考虑ASCII字母和数字)

例:

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

在我能够测试的所有其他9个答案中,到目前为止,这里提出的所有输入中只有两个(由Vincent Zoonekynd和petermeissner撰写)有效,但它们也需要 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 \'] +'似乎更好,因为某些单词在撇号后包含两个以上的字符(例如:时钟)。相关的后续问题:是否有任何方法也可以排除冒号后直接跟数字字符的情况(例如,将“ 10:15”作为一个单词而不是两个单词)?
Thredolsen

2
在此注释中,我将使用纯正则表达式语法,因此示例将需要一些额外的反斜杠。覆盖这样的单词o'clockfriggin'您就可以做到\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

复活5年旧答案的方法!使用“ \ 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
@bartektartanus那是一些不错的功能!
约翰

5
谢谢:)检查此软件包中的其余功能!我相信您会发现一些有趣的事情:)欢迎任何评论!
bartektartanus

7

您可以在库qdap中使用wc函数:

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

6

您可以删除双精度空格并计算" "字符串中的数字以获取单词数。使用stringrrm_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
Adam Bradley13年

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

我发现以下函数和正则表达式可用于字数统计,尤其是在处理单连字符和双连字符时,前者通常不应算作断字,例如,众所周知的高保真;而双连字符是不受空格限制的标点分隔符,例如用于括号的注释。

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
}

产生的列:字符串字符将包含单词和字符的计数,并且对于字符串向量将一次性完成。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.