2011-01-16 5 views
8

У меня есть текстовое поле blob в столбце MySQL, который содержит HTML. Мне нужно изменить часть разметки, поэтому я решил, что сделаю это в рубиновом скрипте. Ruby здесь не имеет значения, но было бы неплохо увидеть ответ с ним. Разметка выглядит следующим образом:поиск и замена ruby ​​regex

<h5>foo</h5> 
    <table> 
    <tbody> 
    </tbody> 
    </table> 

<h5>bar</h5> 
    <table> 
    <tbody> 
    </tbody> 
    </table> 

<h5>meow</h5> 
    <table> 
    <tbody> 
    </tbody> 
    </table> 

мне нужно изменить только первый блок <h5>foo</h5> каждого текста в <h2>something_else</h2>, оставляя остальную часть строки в одиночку.

Невозможно получить правильное регулярное выражение PCRE, используя Ruby.

+2

Я прошу вас рассмотреть использование парсера HTML вместо использования regex для html. Как было сказано [много] (http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags), [много] (http: // stackoverflow. com/questions/590747/using-regular-expressions-to-parse-html-why-not), [много] (http://stackoverflow.com/questions/6751105/why-its-not-possible-to-use -regex-to-parse-html-xml-a-formal-explain-in-la? lq = 1) раз, парсеры Regex неспособны точно анализировать HTML. –

+0

В частности, я рекомендую использовать [Nokogiri] (http://nokogiri.org), чтобы загрузить ваш HTML-код, обработать его, а затем испустить результат. – Phrogz

ответ

31
# The regex literal syntax using %r{...} allows/in your regex without escaping 
new_str = my_str.sub(%r{<h5>[^<]+</h5>}, '<h2>something_else</h2>') 

Использование String#sub вместо String#gsub причины только первая замена произойдет. Если вам нужно динамически выбирать то, что «Foo», вы можете использовать интерполяцию строки в регулярных выражений литералов:

new_str = my_str.sub(%r{<h5>#{searchstr}</h5>}, "<h2>#{replacestr}</h2>") 

Опять же, если вы знаете, что «Foo» есть, вам не нужно регулярное выражение:

new_str = my_str.sub("<h5>searchstr</h5>", "<h2>#{replacestr}</h2>") 

или даже:

my_str[ "<h5>searchstr</h5>" ] = "<h2>#{replacestr}</h2>" 

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

new_str = my_str.sub %r{<h5>([^<]+)</h5>} do |full_match| 
    # The expression returned from this block will be used as the replacement string 
    # $1 will be the matched content between the h5 tags. 
    "<h2>#{replacestr}</h2>" 
end 
+0

Отличный ответ, спасибо – Alp

+0

помогите мне много .. thanx – Jaydipsinh

2

Использование String.gsub с регулярным выражением <h5>[^<]+<\/h5>:

>> current = "<h5>foo</h5>\n <table>\n <tbody>\n </tbody>\n </table>" 
>> updated = current.gsub(/<h5>[^<]+<\/h5>/){"<h2>something_else</h2>"} 
=> "<h2>something_else</h2>\n <table>\n <tbody>\n </tbody>\n </table>" 

Примечание, вы можете проверить рубин регулярное выражение комфортно in your browser.

+0

Ссылка не работает. –

6

Всякий раз, когда мне приходится анализировать или изменять HTML или XML, я добираюсь до парсера. Я почти никогда не беспокоюсь о регулярном выражении, если это абсолютно неинтересно.

Вот как сделать это с помощью Nokogiri, без каких-либо регулярных выражений:

text = <<EOT 
<h5>foo</h5> 
    <table> 
    <tbody> 
    </tbody> 
    </table> 

<h5>bar</h5> 
    <table> 
    <tbody> 
    </tbody> 
    </table> 

<h5>meow</h5> 
    <table> 
    <tbody> 
    </tbody> 
    </table> 
EOT 

require 'nokogiri' 

fragment = Nokogiri::HTML::DocumentFragment.parse(text) 
print fragment.to_html 

fragment.css('h5').select{ |n| n.text == 'foo' }.each do |n| 
    n.name = 'h2' 
    n.content = 'something_else' 
end 

print fragment.to_html 

После разбора, это то, что Nokogiri вернулся из фрагмента:

# >> <h5>foo</h5> 
# >> <table><tbody></tbody></table><h5>bar</h5> 
# >> <table><tbody></tbody></table><h5>meow</h5> 
# >> <table><tbody></tbody></table> 

Это после запуска:

# >> <h2>something_else</h2> 
# >> <table><tbody></tbody></table><h5>bar</h5> 
# >> <table><tbody></tbody></table><h5>meow</h5> 
# >> <table><tbody></tbody></table> 
Смежные вопросы