В Ruby нет «String # substrings_between (start, end)», что мне использовать? - PullRequest
1 голос
/ 09 июля 2010

У меня есть очень сложная строка, например:

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

Теперь я хочу получить детали aaa, bbb, ccc. Я не хочу использовать здесь регулярное выражение, потому что слишком сложно превратить часть <font style="color:red">ABCD@@@EFG^&*))*T*^[][][]</p> в регулярное выражение.

Я надеюсь, что есть метод (скажем, substrings_between), я могу использовать его так:

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

Есть ли такой метод? Или какой лучший способ сделать?

Ответы [ 5 ]

4 голосов
/ 09 июля 2010

В идеале вы должны анализировать HTML, используя правильный синтаксический анализатор, например Nokogiri .

Тем не менее, если вы точно знаете, что то, что вам нужно, находится между двумя жестко закодированными строками, вы можете использовать scan и регулярное выражение:

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

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

substrings = string.scan(/#{before}(.*?)#{after}/).flatten
 => ["aaa", "bbb", "ccc"] 
2 голосов
/ 09 июля 2010

Следующий метод сделает работу

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">ABCD@@@EFG^&*))*T*^[][][]</p>',
'    <p>bbb <font style="color:red">ABCD@@@EFG^&*))*T*^[][][]</p>',
'<p>ccc     cccc<font style="color:red">ABCD@@@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">ABCD@@@EFG^&*))*T*^[][][]</p> Result: |aaa |
String Test = <p>aaa <font style="color:red">ABCD@@@EFG^&*))*T*^[][][]</p> Result: |aaa |
Method Test =     <p>bbb <font style="color:red">ABCD@@@EFG^&*))*T*^[][][]</p> Result: |bbb |
String Test =     <p>bbb <font style="color:red">ABCD@@@EFG^&*))*T*^[][][]</p> Result: |bbb |
Method Test = <p>ccc     cccc<font style="color:red">ABCD@@@EFG^&*))*T*^[][][]</p> Result: |ccc     cccc|
String Test = <p>ccc     cccc<font style="color:red">ABCD@@@EFG^&*))*T*^[][][]</p> Result: |ccc     cccc|

1 голос
/ 09 июля 2010

Я думаю, вам придется создать эту функцию самостоятельно.Что-то вроде:

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, но работает хорошо).

1 голос
/ 09 июля 2010

Я думаю, что искомая функция, вероятно, слишком специфична, чтобы быть в дистрибутиве Ruby.

Вероятно, мы можем собрать ее, используя

String#index(string, offset)

Тогда мы могли бы написать что-то вродеthis (расширение String):

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"]
1 голос
/ 09 июля 2010

Использование strip_tags

string = '<span id="span_is"><br><br><u><i>Hi</i></u></span>'
strip_tags(string)  # Will Return  'Hi'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...