2015-07-03 6 views
1

Я хочу подсчитать количество заглавных букв, чтобы определить процент прописных букв в строке. Я попытался сделать это с регулярным выражением string.match(/[A-Z]*/), но это будет соответствовать только первой комбинации заглавных букв.Подсчет заглавных букв в Ruby

+0

'string.scan (/ [A-Z] /)' –

ответ

4

string.scan() относится ко всей цепочке и должно работать для вашего прецедента. Должно работать следующее:

your_string = "Hello World" 
capital_count = your_string.scan(/[A-Z]/).length 
+1

Я думаю, что вы хотите 'yourString.scan (/ [A-Z] /). Length' – styvane

2

Вот несколько способов, которые не включают преобразование строки в массив символов.

CAPS = ('A'..'Z') 
ALL_CAPS = CAPS.to_a.join 
    #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
CHAR_TO_BIN = 128.times.with_object({}) do |i,h| 
    c = i.chr 
    h[c] = (CAPS.cover?(c) ? 1 : 0) 
end 
    #=> {"\x00"=>0, "\x01"=>0, "\x02"=>0,...," "=>0, "!"=>0,..., 
     "0"=>0, "1"=>0,..."9"=>0, ":"=>0, ";"=>0, "<"=>0, "="=>0, 
     ">"=>0, "?"=>0, "@"=>0, "A"=>1, "B"=>1,..."Z"=>1, "["=>0,..., 
     "a"=>0, "b"=>0,...,"z"=>0, "{"=>0,...,"\x7F"=>0} 

str = "The quick brown dog, 'Lightning', jumped over 'Bubba', the lazy fox" 

1: не очень эффективно, но Быстрейший на сегодняшний день и читает хорошо

str.count(ALL_CAPS) 
    #=> 3 

2: Эффективное

str.each_char.reduce(0) { |t,c| t + (CAPS.cover?(c) ? 1 : 0) } 
    #=> 3 

3: Если вам нужно делайте это много раз (может быть быстрее, чем # 2)

str.each_char.reduce(0) { |t,c| t + CHAR_TO_BIN[c] } 
    #=> 3 

4: Удаление всех не колпачков и сосчитать

str.gsub(/[^A-Z]/,'').size 
    #=> 3 

или удалить все крышки и посчитайте:

str.size - str.gsub(/[A-Z]/,'').size 
    #=> 3 
+0

A downvote? Ну что ж. Может быть, это Бубба, потому что это неправильно? –

1

Я думал, что это было бы интересно сравнить эффективность из предложенных методов.

require 'fruity' 

CAPS = ('A'..'Z') 
ALL_CAPS = CAPS.to_a.join 
    #=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
CHAR_TO_BIN = 128.times.with_object({}) do |i,h| 
    c = i.chr 
    h[c] = (CAPS.cover?(c) ? 1 : 0) 
end 

lower = ('a'..'z').to_a 
upper = ('A'..'Z').to_a 

L = 50_000 
U = 10_000 

Тест строка содержит L случайно нарисованные строчные буквы и U случайно нарисованные букв верхнего регистра, перемешиваются.

str = L.times.map {lower.sample}.concat(U.times.map {upper.sample}).shuffle.join 

compare do 
    scan { str.scan(/[A-Z]/).length } 
    count { str.count(ALL_CAPS) } 
    reduce { str.each_char.reduce(0) { |t,c| t + (CAPS.cover?(c) ? 1 : 0) } } 
    hsh { str.each_char.reduce(0) { |t,c| t + CHAR_TO_BIN[c] } } 
    gsubA { str.gsub(/[^A-Z]/,'').size } 
    gsubB { str.size - str.gsub(/[A-Z]/,'').size } 
end 

Running each test 32 times. Test will take about 33 seconds. 

count is faster than gsubB by 39x ± 10.0 
gsubB is similar to scan 
scan is faster than gsubA by 3x ± 1.0 
gsubA is similar to hsh 
hsh is similar to reduce 

Я был поражен тем, насколько быстро String#count есть. Я предположил, что Ruby сделает include? для каждого символа в строке. Я был неправ. Глядя на исходный код, есть функция Ctr_setup_table, предполагая, что Ruby создает хэш или что-то подобное перед выполнением подсчета.

+0

@theTinMan, я знаю, что вы заинтересованы в тестах; это довольно удивительно. –

Смежные вопросы