2016-10-07 2 views
1

У меня есть строка a5bc2cdf3. Я хочу расширить его до aaaaabcbccdfcdfcdf.Как расширить строку в Ruby на основе некоторого условия?

В строке является a5, так что результирующая строка должна содержать 5 последовательных «а» S «» bc2 результаты в «БК» появляются в 2 раза последовательно, и cdf должен повторить 3 раз.

Если ввод a5bc2cdf3, а вывод - aaaaabcbccdfcdfcdf, как я могу сделать это в рубиновом методе?

def get_character("compressed_string",index) 
    expanded_string = calculate_expanded_string(compressed_string) 
    required_char = expanded_string(char_at, index_number(for eg 3)) 
end 

def calculate_expanded_string(compressed_string) 
    return expanded 
end 
+0

Обратите внимание на правильную грамматику. «i» - это «я». Stack Overflow - это онлайн-справочник, а не список дискуссий, а также грамматика, орфография, пунктуация и форматирование. –

ответ

3

Вы можете использовать регулярное выражение как

.gsub(/([a-zA-Z]+)(\d+)/){$1*$2.to_i} 

Посмотреть Ruby online demo

/([a-zA-Z]+)(\d+)/ будет соответствовать stubstrings с 1+ буквами (([a-zA-Z]+)) и 1+ цифр ((\d+)) и захватить их в 2 группы, которые позже используются внутри блока для возврата нужной вам строки.

Обратите внимание, что вместо [a-zA-Z] вы можете использовать \p{L}, которые могут совпадать с любыми буквами.

Вы хотите вырваться из gsub после достижения указанного индекса в исходной «сжатой» строке. Это все еще возможно, увидеть this Ruby demo:

s = 'a5bc2cdf3'    # input string 
index = 5      # break index 
result = ""     # expanded string 
s.gsub!(/([a-zA-Z]+)(\d+)/){ # regex replacement 
    result << $1*$2.to_i  # add to the resulting string 
    break if Regexp.last_match.end(0) >= index # Break if the current match end index is bigger or equal to index 
} 
puts result[index]   # Show the result 
# => b 

Для краткости, вы можете заменить Regexp.last_match с $~.

+0

, но здесь мы знаем, что на каких позициях число присутствует. что, если строка динамически добавляется к этому методу, поскольку мы не знаем, сколько чисел присутствует, и на каких позициях присутствуют цифры? – John

+0

Просто уточнить: вы хотите ограничить количество расширений? Что должен делать «индекс»? –

+0

в расширенной строке «aaaaabcbccdfcdfcdf» (передача индекса). то есть «5», тогда я должен получить «b» chracter, поскольку индекс начинается с нуля. – John

2

Я бы предложил использовать scan для перемещения по сжатой строке с использованием простого RegEx, который обнаруживает группы не десятичных знаков, за которыми следует их число как десятичное /([^\d]+)(\d+)/.

def get_character(compressed_string, index) 
    result = nil 

    compressed_string.scan(/([^\d]+)(\d+)/).inject(0) do |total_length, (chars, count)| 
    decoded_string = chars * count.to_i 
    total_length += decoded_string.length 

    if index < total_length 
     result = decoded_string[-(total_length - index)] 
     break 
    else 
     total_length 
    end 
    end 

    result 
end 

Зная текущую (общую) длину, вы можете выйти из цикла, если текущая расширенная строка содержит запрошенный индекс. Строка никогда не расшифровывается полностью.

Этот код дает следующие результаты

get_character("a5bc2cdf3", 5) # => "b" 
get_character("a5bc2cdf3", 10) # => "d" 
get_character("a5bc2cdf3", 20) # => nil 
+0

Просто хотел добавить, что этот фрагмент работает таким образом из-за комментариев на Wiktors, например. что код должен прекратить декомпрессию ввода, если индекс достигнут. –

0

Просто еще один способ. Я предпочитаю метод Wiktor долгий путь.

def stringy str, index 
    lets, nums = str.split(/\d+/), str.split(/[a-z]+/)[1..-1].map(&:to_i) 
    ostr = lets.zip(nums).map { |l,n| l*n }.join 
    ostr[index] 
end 

str = 'a5bc2cdf3' 
p stringy str, 5 #=> "b" 
0

Я хотел бы использовать:

str = "a5bc2cdf3" 
str.split(/(\d+)/).each_slice(2).map { |s, c| s * c.to_i }.join # => "aaaaabcbccdfcdfcdf" 

Вот как она ломается:

str.split(/(\d+)/) # => ["a", "5", "bc", "2", "cdf", "3"] 

Это работает, потому что split возвратит значение раскалывается на если это в регулярное выражение группы: /(\d+)/.

str.split(/(\d+)/).each_slice(2).to_a # => [["a", "5"], ["bc", "2"], ["cdf", "3"]] 

Полученный массив может быть разбит на строки, которая будет повторяться и связанный с ним счетчик с помощью each_slice(2).

str.split(/(\d+)/).each_slice(2).map { |s, c| s * c.to_i } # => ["aaaaa", "bcbc", "cdfcdfcdf"] 

Этот массив массивов могут быть обработаны в map, который использует струны * повторять символы.

И, наконец, join объединяет все полученные развернутые строки обратно в одну строку.

Смежные вопросы