在Ruby中计算字符串中单词数量的最佳方法是什么?

33

有没有比 string.scan(/(\w|-)+/).size 更好的方法呢?(其中 - 的作用是使像 "one-way street" 这样的字符串被计为 2 个单词而不是 3 个单词)


6
“单词”一词的定义是什么?请想象以下字符串:“I am ... string.”,您希望计算多少个单词? - Christoph Schiessl
非常好的问题,亲爱的。 - Manish Shrivastava
8个回答

60
string.split.size

解释多个空格的编辑

Ruby String文档页面

split(pattern=$;, [limit]) → anArray

根据分隔符将str拆分为子字符串,并返回这些子字符串的数组。

如果pattern是一个字符串,则在拆分str时使用其内容作为分隔符。 如果pattern是单个空格,则在分割str时会忽略前导空格和连续的空格字符。

如果pattern是一个正则表达式,则在模式匹配的地方将str分割。每当模式匹配零长度字符串时,str将被分割为单个字符。 如果pattern包含组,则相应的匹配结果也将在数组中返回。

如果省略了pattern,则使用$;的值。如果$;为nil(默认值),则与指定了“ ”一样,在空格处拆分str。

如果省略了limit参数,则省略尾随的null字段。如果limit是正数,则最多返回那么多个字段(如果limit为1,则整个字符串作为数组中的唯一条目返回)。如果是负数,则没有限制返回字段的数量,并且不省略尾随的null字段。

" now's  the time".split        #=> ["now's", "the", "time"]

虽然这篇编辑时的最新 ruby 版本是如此,但我是在 1.7 版本(如果我没记错的话)学会这个技巧的,那个版本也可以用这种方式。我刚在 1.8.3 版本上测试过了。


这个解决方案也将空格视为单词(空),请考虑这一点。 - damuz91
1
@DavidMauricio 不会。 split 没有参数时默认在空格上分割。(好吧,它会在 $; 上分割,但如果 $; 也是 nil,那么它将在空格上分割。) Ruby 文档将此行为描述为“忽略前导空格和连续空格字符的运行”。 - KitsuneYMG
2
这样做是否会不必要地创建单词数组以返回其大小?如果文本中有10,000个单词怎么办?这将浪费空间并因此变慢。 - Ernesto
@Ernesto 是的,实际上,你可以通过这种方式每秒计算数百万个单词,并且数组会被垃圾回收。过早优化之类的问题。 - Robert Head

12
我知道这是一个老问题,但对于寻找比string.split更复杂的东西的其他人来说,这可能会很有用。我编写了words_counted gem来解决这个特定的问题,因为定义单词非常棘手。
这个gem允许你定义自己的自定义标准,或者使用开箱即用的正则表达式,对于大多数用例来说非常方便。您可以使用各种选项预过滤单词,包括字符串、lambda、数组或另一个正则表达式。
counter = WordsCounted::Counter.new("Hello, Renée! 123")
counter.word_count #=> 2
counter.words #=> ["Hello", "Renée"]

# filter the word "hello"
counter = WordsCounted::Counter.new("Hello, Renée!", reject: "Hello")
counter.word_count #=> 1
counter.words #=> ["Renée"]

# Count numbers only
counter = WordsCounted::Counter.new("Hello, Renée! 123", rexexp: /[0-9]/)
counter.word_count #=> 1
counter.words #=> ["123"]

这个宝石提供了一堆更有用的方法


2
如果这里的'word'可以描述为包含'-'的字母数字序列,则以下解决方案可能是合适的(假设不匹配'word'模式的所有内容都是分隔符):

>> 'one-way street'.split(/[^-a-zA-Z]/).size
=> 2
>> 'one-way street'.split(/[^-a-zA-Z]/).each { |m| puts m }
one-way
street
=> ["one-way", "street"]

然而,还有一些其他符号可以包含在正则表达式中 - 比如,'以支持像"it's"这样的单词。

1
这很简单,如果你输入的是带空格的单词,它就能完成任务。它最终也会计算数字,但我相信你可以编辑代码以不计算数字。
puts "enter a sentence to find its word length: "
word = gets
word = word.chomp
splits = word.split(" ")
target = splits.length.to_s


puts "your sentence is " + target + " words long"

1
最好的方法是使用split方法。 split根据分隔符将字符串分成子字符串,返回一个子字符串数组。 split接受两个参数,即patternlimitpattern是要将字符串拆分为数组的分隔符。 limit指定结果数组中的元素数量。 有关详细信息,请参阅Ruby文档:Ruby字符串文档
str = "This is a string"
str.split(' ').size
#output: 4

上面的代码在找到一个空格时拆分字符串,因此它给出了字符串中单词的数量,这间接地表示数组的大小。

0

上述解决方案是错误的,请考虑以下内容:

"one-way  street"

你将会得到

["one-way","", "street"]

使用

'one-way street'.gsub(/[^-a-zA-Z]/, ' ').split.size

1
在单向和街道之间,有2个空格。 - Hillel
8
不行。如果没有提供参数且 $;nil,Ruby 会根据空格(连续的、前导和尾随的空格将被忽略,例如 \s+)进行分割。请学习 Ruby。 - KitsuneYMG

0

这只在 ASCII 空白字符上分割单词:

p "  some word\nother\tword|word".strip.split(/\s+/).size #=> 4

0
例如,在文件中计算《战争与和平》的字数。
acc = 0
File.readlines('war_and_peace.txt').each { |line| acc += line.split.size }

acc
 => 238610

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接