2010-07-09 26 views
1

我有一個非常複雜的字符串,如:Ruby沒有「String#substrings_between(start,end)」,應該使用什麼?

<p>aaa <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> 
<p>bbb <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> 
<p>ccc <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> 
.... 

現在我想要得到的aaabbbccc部分。我不想在這裏使用正則表達式,因爲將<font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p>部分轉換爲正則表達式太複雜了。

我希望有一種方法(比如substrings_between),我可以用它像這樣:

substrings = text.substrings_between('<p>', ' <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p>'); 
substrings # -> [aaa, bbb, ccc] 

有沒有這樣的方法?或者最好的辦法是什麼?

+1

您使用的是'font'標籤應該已經很久沒有被埋沒了,使用內聯樣式而不是CSS類,拼錯'style'屬性,都在同一行? – 2010-07-09 12:30:58

+0

我想要做的是從網頁上獲取一些消息。這就是該頁面的內容。 – Freewind 2010-07-09 12:49:06

+0

@Mike,謝謝你的編輯。我的錯別字:) – Freewind 2010-07-09 12:50:50

回答

4

理想情況下,你應該使用合適解析器,像Nokogiri解析HTML。

這就是說,如果你肯定知道你需要的是位於兩個硬編碼字符串之間的東西,你可以使用掃描和正則表達式:

string = '<p>aaa <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> 
      <p>bbb <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> 
      <p>ccc <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p>' 

before = Regexp.escape '<p>' 
after = Regexp.escape ' <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p>' 

substrings = string.scan(/#{before}(.*?)#{after}/).flatten 
=> ["aaa", "bbb", "ccc"] 
+0

D'oh!我忘記了'Regexp#escape'! – 2010-07-09 15:41:31

+0

你的代碼看起來很簡單很好,謝謝:) – Freewind 2010-07-13 02:23:11

1

使用strip_tags

string = '<span id="span_is"><br><br><u><i>Hi</i></u></span>' 
strip_tags(string) # Will Return 'Hi' 
+0

謝謝。我的任務比這更難,所以我想要的不僅僅是條形標籤,而是獲得一些關鍵字之間的子串。 – Freewind 2010-07-09 12:40:05

1

我認爲你必須建立自己的功能。例如:

def substrings_between str, opening, ending 
    i_opening = str.index opening 
    i_ending = str.index ending 
    res = [] 
    while i_opening && i_ending 
    res << str[i_opening+opening.length .. i_ending] 
    str = str[i_ending+ending.length .. -1] 
    i_opening = str.index opening 
    i_ending = str.index ending 
    end 
    res 
end 

(這段代碼並不像Ruby那麼多,但效果很好)。

+0

謝謝。有一個小錯誤:'i_ending = str.index ending'應該是'str.index結尾,i_opening +開頭。長度' – Freewind 2010-07-13 02:30:47

+0

@Freewind,你是什麼意思?它的代碼似乎爲我工作,並改變i.ending = str.index結束str.index結束,i_opening + opening.length給出了一個錯誤(我不明白你的意圖)。 – paradoja 2010-07-13 10:57:00

+0

請嘗試'substrings_between「abcba」,「b」,「a」',結果是'[「」,「cba」]'。我認爲正確的結果應該是'[「cb」]' – Freewind 2010-07-13 13:57:38

1

我認爲你正在尋找的功能可能過於具體,不適合Ruby分發。

我們可以通過

String#index(string, offset) 

然後,我們可以寫這樣的事情可能進行組裝(擴展字符串):

class String 
    def delimited_strings(start_delim, end_delim) 
    strings = [] 
    starts_at = index(start_delim) 
    return strings unless starts_at 
    ends_at = index(end_delim, starts_at + start_delim.size) 
    while starts_at && ends_at do 
     strings << self[starts_at+start_delim.size...ends_at] 
     starts_at = index(start_delim, starts_at + end_delim.size) 
     ends_at = index(end_delim, starts_at + start_delim.size) if starts_at 
    end 
    strings 
    end 
end 

s = "<p>aaa<font>xxx</font></p><p>bbb<font>xxx</font></p><p>ccc<font>xxx</font></p>" 
s.delimited_strings("<p>", "<font") #=> ["aaa", "bbb", "ccc"] 
+0

謝謝!有一個小小的錯誤嗎? 'ends_at = index(end_delim,starts_at + 1' =>'ends_at = index(end_delim,starts_at + start_delim.length'?我認爲'+ 1'是不夠的,如果考慮'start_delin = abc,end_delim = bc' – Freewind 2010-07-13 02:33:01

+0

@Freewind - eek,你是對的,測試條件不足,代碼改爲(希望)會更有彈性... – 2010-07-13 07:51:28

2

下面的方法將做的工作

def substring_between(target, match1, match2) 
    start_match1 = target.index(match1) 
    if start_match1 && start_match2 = target.index(match2, start_match1 + match1.length) 
    start_idx = start_match1 + match1.length 
    target[start_idx, start_match2 - start_idx] 
    else 
    nil 
    end 
end 

如果你想創建這個作爲字符串類的實例方法,那麼這應該爲你工作

class String 
    def substring_between(sub1, sub2) 
    match1 = self.index(sub1) 
    if match1 && match2 = self.index(sub2, match1 + sub1.length) 
     idx = match1 + sub1.length 
     self[idx, match2 - idx] 
    else 
     nil 
    end 
    end 
end 

如果開始或結束標記不存在或順序錯誤,那麼兩個實現都會返回nil。下面的測試腳本和結果表明,它的工作

strings = [ 
'No tags at all', 
'<font End tag before start tag <p>', 
'<p>End tag at end <font', 
'No start tag <font', 
'<p>No end tag', 
'<p>aaa <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p>', 
' <p>bbb <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p>', 
'<p>ccc  cccc<font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p>' 
] 

strings.each do |s| 
    puts "Method Test = #{s} Result: |#{substring_between(s, '<p>', '<font')}|" 
    puts "String Test = #{s} Result: |#{s.substring_between('<p>', '<font')}|" 
end 
 
Method Test = No tags at all Result: || 
String Test = No tags at all Result: || 
Method Test = <font End tag before start tag <p> Result: || 
String Test = <font End tag before start tag <p> Result: || 
Method Test = <p>End tag at end <font Result: |End tag at end | 
String Test = <p>End tag at end <font Result: |End tag at end | 
Method Test = No start tag <font Result: || 
String Test = No start tag <font Result: || 
Method Test = <p>No end tag Result: || 
String Test = <p>No end tag Result: || 
Method Test = <p>aaa <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> Result: |aaa | 
String Test = <p>aaa <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> Result: |aaa | 
Method Test =  <p>bbb <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> Result: |bbb | 
String Test =  <p>bbb <font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> Result: |bbb | 
Method Test = <p>ccc  cccc<font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> Result: |ccc  cccc| 
String Test = <p>ccc  cccc<font style="color:red">[email protected]@@EFG^&*))*T*^[][][]</p> Result: |ccc  cccc| 

+0

感謝您的詳細解答,您給了我有用的技巧,雖然我想在這裏是「substring ** s * * _between「,但同樣謝謝你 – Freewind 2010-07-13 02:28:12

相關問題