Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Ruby: Общие вопросы > Как измененить все фрагменты найденные регуляркой?


Автор: Bose 23.10.2009, 16:44
Скажу сразу, с Руби столкнулся всего пару дней назад и не по велению души, а по необходимости. 

Задача, по-видимому, тривиальная.

Дано: на входе строка(содержащая в себе фрагмент html). 
Нужно заменить все упоминания текста "а" на "@", не изменяя html-тэги.

Например, есть текст:
Код

<div class="wiki"> 
  <h1 id="Header1">Header1<a href="#Compile" class="wiki-anchor">&para;</a></h1> 
    <h2 id="Header2">Header 2<a href="#Compiler-directives" class="wiki-anchor">&para;</a></h2> 
    <p>Some another text;</p> 
    <p><a href="http://www.example.com">another link</a></p> 
</div> 


Нужно чтобы замена произошла только в тексте, не изменяя тэги. Т.е. чтобы
Header 1 => He@der 1
Header 2 => He@der 2
Some another text; -> Some @nother text;
another link -> @nother link

Как такое сделать правильно (желательно стандартными средствами Ruby + Rails + регулярки)?

Автор: source777 25.10.2009, 23:15
Цитата(Bose @  23.10.2009,  16:44 Найти цитируемый пост)
Задача, по-видимому, тривиальная.

Задача вообще-то довольно сложная, если решать её одним регулярным выражением. 
Но в Ruby решается довольно просто, т.к. gsub может принимать блок:
Код

  puts text.gsub(/>.*?</) { |m| m.gsub('a', '@') }

На выходе:
Цитата

<div class="wiki"> 
  <h1 id="Header1">He@der1<a href="#Compile" class="wiki-anchor">&p@r@;</a></h1> 
    <h2 id="Header2">He@der 2<a href="#Compiler-directives" class="wiki-anchor">&p@r@;</a></h2> 
    <p>Some @nother text;</p> 
    <p><a href="http://www.example.com">@nother link</a></p> 
</div>

Автор: Bose 26.10.2009, 02:25
source777, спасибо за ответ. Он мне действительно помог.

Я не очень точно сформулировал задачу.  
Это необязательно должно быть регулярное выражение. Просто насколько я понимаю, с регулярками такое сделать проще всего.

Очень важное уточнение (сорри, я облажался, что не упомянул о нём когда задавал вопрос): 
с найденным текстом, не являющимся тегом нужно провести несколько операций замены. 

Пока что я сделал так (признаюсь, что большая часть кода - это copy&paste, и некоторых вещей я ещё не понимаю. Например - зачем нужна собачка перед @my_rules):
Код

    MY_RULES = [['redmine','"redmine":http://www.redmine.org'],['radio','[[radio]]']]
    def inline_my( text )
       @my_rules = MY_RULES.collect do |my_rule|
         text.gsub!(/>.*?</) { |m| m.gsub( my_rule[0], my_rule[1]) }
       end.flatten
     end


Правила по замене у меня пока хранятся в массиве. (когда научусь , я их буду загружать из БД). 

По ходу тестирования появились ещё 2 вопроса:
1) Не будет ли эффективнее поменять циклы замены местами? Чтобы сначала происходил поиск текста по />.*?</ а уже потом, цикл по элементам массива? Если да, то как такое сделать? smile
2) Как сделать, чтобы поиск текста из my_rule[0] был нечувствительным к РеГистру? (case insensitive)? 

Избавится от чувствительности к Регистру я смог, только заменив текст в массиве с
'redmin' на /redmine/i
но это мне кажется неудобным. Есть ли какой способ добавить опцию /i на лету? Или отключить чувствительность к регистру только для этой замены (не глобально)?
Код

    MY_RULES = [[/redmine/i,'"redmine":http://www.redmine.org'],['radio','[[radio]]']]


Автор: source777 26.10.2009, 19:14
Цитата(Bose @  26.10.2009,  02:25 Найти цитируемый пост)
Как сделать, чтобы поиск текста из my_rule[0] был нечувствительным к РеГистру? (case insensitive)? 

http://www.ruby-doc.org/core/classes/String.html#M000817 может принимать для поиска как строку, так и регулярное выражение:
Код

  rules = {'redmine' => '"redmine":http://www.redmine.org', 'radio' => '[[radio]]'}
  rules.each do |term, replacement|
    text.gsub!(/>.*?</) { |m| m.gsub(/#{term}/i, replacement) }
  end


Цитата(Bose @  26.10.2009,  02:25 Найти цитируемый пост)
Не будет ли эффективнее поменять циклы замены местами? 

Возможно и будет, http://ruby-doc.org/stdlib/libdoc/benchmark/rdoc/index.html тебе в помощь. 
Несколько замен можно сделать прямо в блоке, передаваемом gsub, главное чтобы блок возвращал итоговый результат.



Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)