Как заменить каждое вхождение шаблона в строке, используя Ruby? - PullRequest
1 голос
/ 15 декабря 2010

У меня есть слишком большой XML-файл.Чтобы уменьшить его, я хочу заменить все теги и имена атрибутов на более короткие версии одного и того же.

Итак, я реализовал это:

string.gsub!(/<(\w+) /) do |match|
    case match
    when 'Image' then 'Img'
    when 'Text'  then 'Txt'
    end
end

puts string

, который удаляет все открывающие теги, нобольше ничего не делать.

Что я здесь не так делаю?

Ответы [ 3 ]

2 голосов
/ 15 декабря 2010

Вот еще один способ:

class String
  def minimize_tags!
    {"image" => "img", "text" => "txt"}.each do |from,to|
      gsub!(/<#{from}\b/i,"<#{to}")
      gsub!(/<\/#{from}>/i,"<\/#{to}>")
    end
    self
  end
end

Это, вероятно, будет немного легче поддерживать, поскольку шаблоны замены находятся в одном месте. А на струнах любого значительного размера это может быть намного быстрее, чем у Кевина. Я провел быстрое тестирование скорости этих двух методов, используя исходный код HTML этой страницы stackoverflow в качестве тестовой строки, и мой путь был примерно в 6 раз быстрее ...

2 голосов
/ 16 декабря 2010

Вот прелесть использования парсера, такого как Nokogiri :

Это позволяет вам манипулировать выбранными тегами (узлами) и их атрибутами:

require 'nokogiri'

xml = <<EOT
<xml>
  <Image ImagePath="path/to/image">image comment</Image>
  <Text TextFont="courier" TextSize="9">this is the text</Text>
</xml>
EOT

doc = Nokogiri::XML(xml)
doc.search('Image').each do |n| 
  n.name = 'img' 
  n.attributes['ImagePath'].name = 'path'
end
doc.search('Text').each do |n| 
  n.name = 'txt'
  n.attributes['TextFont'].name = 'font'
  n.attributes['TextSize'].name = 'size'
end
print doc.to_xml
# >> <?xml version="1.0"?>
# >> <xml>
# >>   <img path="path/to/image">image comment</img>
# >>   <txt font="courier" size="9">this is the text</txt>
# >> </xml>

Если вынужно перебрать каждый узел, может быть, чтобы сделать универсальное преобразование имени тега, вы можете использовать doc.search('*').each.Это будет медленнее, чем поиск отдельных тегов, но может привести к меньшему количеству кода, если вам потребуется изменить каждый тег.

Хорошая особенность использования парсера в том, что он будет работать, даже если макет XML изменяетсяпоскольку он не заботится о пробелах и будет работать даже при изменении порядка атрибутов, делая ваш код более надежным.

1 голос
/ 15 декабря 2010

Попробуйте это:

string.gsub!(/(<\/?)(\w+)/) do |match|
  tag_mark = $1
  case $2
  when /^image$/i
    "#{tag_mark}Img"
  when /^text$/i
    "#{tag_mark}Txt"
  else
    match
  end
end  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...