2009-11-30 56 views
18

我試圖使用Ruby將索引返回到字符串中特定字符的所有匹配項。示例字符串是"a#asg#sdfg#d##",當搜索#字符時預期回報爲[1,5,10,12,13]。下面的代碼可以完成這項工作,但是必須有一個更簡單的方法來做到這一點?返回ruby中字符串中所有字符的索引

def occurances (line) 

    index = 0 
    all_index = [] 

    line.each_byte do |x| 
    if x == '#'[0] then 
     all_index << index 
    end 
    index += 1 
    end 

    all_index 
end 

回答

15
s = "a#asg#sdfg#d##" 
a = (0 ... s.length).find_all { |i| s[i,1] == '#' } 
+3

s =「a#asg#sdfg#d ##」 a =(0 ... s.length).find_all {| i | s [i] =='#'}應該工作得對嗎?不需要,1 ...? –

+0

@SamJoseph在這種情況下,是的,兩者是同義詞。 '[x,y]'的2個參數版本意味着「從'x'開始的長度爲'y'的子字符串,它與'[x]'相同,這意味着」字符在'x'(也是一個字符串,因爲紅寶石沒有Char類型)「。 – erich2k8

15
require 'enumerator' # Needed in 1.8.6 only 
"1#3#a#".enum_for(:scan,/#/).map { Regexp.last_match.begin(0) } 
#=> [1, 3, 5] 

ETA:這是通過創建一個使用scan(/#/)爲每個方法的枚舉。

掃描會產生指定模式(在本例中爲/#/)的每次出現,並且在塊內您可以調用Regexp.last_match來訪問匹配的MatchData對象。

MatchData#begin(0)返回匹配開始處的索引,並且由於我們在枚舉數上使用了map,我們得到了這些索引的數組。

+1

酷,但我不知道這是如何工作的。 – Gerhard

2

這是一個漫長的方法鏈:

"a#asg#sdfg#d##". 
    each_char. 
    each_with_index. 
    inject([]) do |indices, (char, idx)| 
    indices << idx if char == "#" 
    indices 
    end 

# => [1, 5, 10, 12, 13] 

需要1.8.7+

+0

在1.9中,您可以執行'.each_char.with_index'(而不是'each_char.each_with_index')。我認爲,它讀得更好。 – Telemachus

+0

確實如此。 –

12

這裏有一個花哨更低的方式:

i = -1 
all = [] 
while i = x.index('#',i+1) 
    all << i 
end 
all 

在快速的速度測試,這是大約比FM的find_all方法快3.3倍,比sepp2k的enum_for方法快大約2.5倍。

+0

那些速度數字是從1.8.5。在1.9.1中,這仍然是最快的,但find_all大約慢了3倍,而enum_for大約慢了5倍! –

+0

我的猜測是它是'Regexp.last_match.begin(0)',它正在減慢'enum_for'方法的速度。 (也就是說,我希望'enum_for'本身不是問題。)無論哪種方式,我都喜歡它,它既簡單又可讀。不那麼花俏通常更好。 – Telemachus

+0

這樣做更快,因爲其他方法中的每個字符都會執行一個塊。我遇到並解決了類似的問題,在http://stackoverflow.com/questions/6387428/why-is-counting-letters-faster-using-stringcount-than-using-stringchars-in-ruby/6475413#6475413 –

1

從FMC的回答得到的另一個解決方案:

s = "a#asg#sdfg#d##" 
q = [] 
s.length.times {|i| q << i if s[i,1] == '#'} 

我喜歡紅寶石從來沒有做的事情只有一個辦法!

相關問題