Использовать выражение регулярных выражений в карте замен gsub?
Я пытаюсь заставить это работать:
def self.simultaneos_gsub(arguments)
map_of_regex = Hash[arguments]
re = Regexp.union(map_of_regex.keys)
s = self.gsub(re, map_of_regex)
end
Аргументы будут примерно такими:
[[/[0-9]/i, '-'], [/@/, 'T']]
Так "019@hey"
должен вернуться "---They"
,
Лучший пример того, что я хочу, это:
arguments = [[/[a-z]/i, '@'], [/@/, '-']]
Input: 'This is just a @234' should return => '@@@ @@ @@@@ @ -234'
gsub
находит правильные символы, но заменяет их пустыми.
Есть идеи?
4 ответа
[18] pry(main)> s = "019@hey"
=> "019@hey"
[19] pry(main)> [[/[0-9]/i, '-'], [/@/, 'T']].each { |k,v| s.gsub!(k, v) }
=> [[/[0-9]/i, "-"], [/@/, "T"]]
[20] pry(main)> s
=> "---They"
переписанный метод, поэтому args может быть хешем, например { /[0-9]/i => '-', /@/ => 'T' }
или массив, содержащий массивы, каждый из которых имеет 2 элемента, например [[/[0-9]/i, '-'], [/@/, 'T']]
def simultaneous_gsub(string, args)
st = string.dup
args.each { |k,v| st = st.gsub(k, v) }
st
end
Пример использования:
string = "019@hey"
simultaneous_gsub(string, { /[0-9]/i => '-', /@/ => 'T' })
#=> "---They"
or
string = "019@hey"
simultaneous_gsub(string, [[/[0-9]/i, '-'], [/@/, 'T']])
#=> "---They"
Может быть, это поможет разложить вещи:
class String
def simultaneos_gsub(arguments)
map_of_regex = Hash[arguments]
re = Regexp.union(map_of_regex.keys) # => /0|1|2|3|4|5|6|7|8|9|@/, /a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|@|T/
self.gsub(re, map_of_regex) # => "---They", "@@@@ @@ @@@@ @ -234"
end
end
arguments = Hash[('0'..'9').zip(['-'] * 10)]
arguments['@'] = 'T'
arguments # => {"0"=>"-", "1"=>"-", "2"=>"-", "3"=>"-", "4"=>"-", "5"=>"-", "6"=>"-", "7"=>"-", "8"=>"-", "9"=>"-", "@"=>"T"}
"019@hey".simultaneos_gsub(arguments) # => "---They"
arguments = Hash[('a' .. 'z').zip(['@'] * 26)]
arguments.merge!({'@' => '-', 'T' => '@'})
# should return => '@@@ @@ @@@@ @ -234'
'This is just a @234'.simultaneos_gsub(arguments) # => "@@@@ @@ @@@@ @ -234"
Ключи хеша передаются gsub
это не шаблоны регулярных выражений, это значения, которые были найдены в строке. Ключи должны быть превращены в шаблон для первого параметра gsub
,
Если вам действительно нужно, чтобы gsub выполнялся в одной строке, вы можете создать хеш, представляющий все возможные символы соответствия, сопоставленные с их символом замены. Документация относительно предоставления хеша в качестве аргумента gsub
можно найти здесь
Вот код, который может это сделать. Это не красиво, но кажется, что вы довольно gsub
вызывается только один раз.
Вот что я бы сделал:
# Create a hash that looks like this...
# replacement_hash = {
# 'a' => '@',
# 'b' => '@',
# ...
# 'Z' => '@',
# '@' => '-' }
replacement_hash = {}
(('a'..'z').to_a + ('A'..'Z').to_a).each { |char| replacement_hash[char] = '@' }
replacement_hash['@'] = '-'
'This is just a @234'.gsub(/[a-zA-Z\@]/, replacement_hash) # => "@@@@ @@ @@@@ @ -234"
Предостережения
Чтобы получить эту работу в рамках вашей функции, вам необходимо предоставить карту сопоставленных строк с их соответствующими заменами. Тогда ваше регулярное выражение должно быть чередованием (|
) между всеми этими возможными поисковыми строками. Это немного легче осуществить, как указано выше, когда это просто один символ, замененный другим символом / символом /.
Если вы не женаты на gsub
Вы можете сделать это с помощью рекурсии, split
, а также join
:
class String
def simultaneos_gsub(arguments)
if arguments.empty?
self
else
argument = arguments.pop
parts = split(argument.first)
parts.collect! {|part| part.simultaneos_gsub(arguments) }
parts.join(argument.last)
end
end
end
arguments = [[/[a-z]/i, "@"], [/@/, "-"]]
string = "This is just a @234"
string.simultaneos_gsub(arguments)
#=> "@@@@ @@ @@@@ @ -234"
Это позволяет избежать проблемы, которую, я полагаю, вы пытаетесь решить gsub
Часть строки, которую вы уже заменили несколько раз, удаляет части строки, которую вы заменяете, а затем добавляете их обратно в качестве значения замены.