2015-08-08 6 views
0

Я изо всех сил пытаюсь извлечь значения ID и ответа из строки, отправленной из приложения iOS. В следующем примере у меня есть четыре идентификатора и четыре ответа, которые нужно извлечь.Извлечение значений из длинной строки

s = "ID:1_Answer1_ID:2_Answer2_ID:3_AnswerRandom_ID:789_Answer3.5" 

IDs_array = [1,2,3,789] 
Answers_array = [Answer1,Answer2,AnswerRandom,Answer3.5] 

Оцените справку или помощь.

ответ

5
ids, answers = s.scan(/ID:(\d+)_([^_]+)/).transpose 

Идея регулярное выражение:

  1. Идентификаторы предшествует ID: - ID:
  2. Фактические идентификаторы являются числами - (\d+)
  3. Они разделены от ответов с подчеркиванием - _
  4. В ответы сами собой последовательность без подчеркивания символов ([^_]+)

String#scan с обратным массивом пар массивов [id, answer], поэтому перенесем его, чтобы получить два массива - один с идентификаторами и один с ответы. Затем мы используем множественное назначение, которое распаковывает внешний массив.

+0

хорошее решение и хорошее объяснение. –

+0

Очень чистое решение. Спасибо огромное! – rak

+0

Однако он не фиксирует пустое значение ответа. Например, вопрос 1 не имеет ответа. s = "ID: 1__ID: 2_Answer2_ID: 3_AnswerRandom_ID: 789_Answer3.5" – rak

-1

Просьба уточнить ваш вопрос.

Нужны ли идентификаторы и ответы? они всегда попарно? Является ли символ "_" всегда используемым как разделитель (это означает, что ответы должны быть закодированы)? Является ли формат всегда:

"ID:#{id_mumber}_#{answer in text}" ... "_" ... *

я буду считать, ответ на все вопросы, которые я задал в «Да», но если я ошибаюсь, пожалуйста, измените ваш вопрос оставьте мне комментарий - я отредактирую ответ.

s = "ID:1_Answer1_ID:2_Answer2_ID:3_AnswerRandom_ID:789_Answer3.5" 

answer_hash = {} 

tmp = s.split('_') 

answer_hash[tmp.shift[3..-1].to_i] = tmp.shift while tmp[0] 

answer_hash # => {1=>"Answer1", 2=>"Answer2", 3=>"AnswerRandom", 789=>"Answer3.5"} 
answer_hash.keys # => [1, 2, 3, 789] 
answer_hash.values # => ["Answer1", "Answer2", "AnswerRandom", "Answer3.5"] 

EDIT

Я любил @ ответ NDN в использовании Regexp ... Это ясно, но может быть медленнее для коротких строк.

Вот тесты на моей машине - Они показывают, что разница в производительности в основном для коротких строк ID:

s = "ID:1_Answer1_ID:2_Answer2_ID:3_AnswerRandom_ID:789_Answer3.5" 

puts Benchmark.measure {100_000.times {answer_hash = {}; tmp = s.split('_'); answer_hash[tmp.shift[3..-1].to_i] = tmp.shift while tmp[0] } } 

# ### Short string using str 
# => 0.280000 0.000000 0.280000 ( 0.286917) 

puts Benchmark.measure {100_000.times {ids, answers = *s.scan(/(?<=ID:)(\d+)_([^_]+)/).transpose } } 

# ### Short string using string.scan Regexp 
# => 0.590000 0.000000 0.590000 ( 0.595052) 



s = [] 
100.times {|i| s << ("ID:#{i}_Answer#{i}") } 
s = s.join('_') 



puts Benchmark.measure {100_000.times {answer_hash = {}; tmp = s.split('_'); answer_hash[tmp.shift[3..-1].to_i] = tmp.shift while tmp[0] } } 

# ### Medium string using string.split 
# => 7.180000 0.010000 7.190000 ( 7.213266) 


puts Benchmark.measure {100_000.times {ids, answers = *s.scan(/(?<=ID:)(\d+)_([^_]+)/).transpose } } 

# ### Medium string using string.scan Regexp 
# => 8.860000 0.020000 8.880000 ( 8.888352) 



s = [] 
1000.times {|i| s << ("ID:#{i}_Answer#{i}") } 
s = s.join('_') 


puts Benchmark.measure {1000.times {answer_hash = {}; tmp = s.split('_'); answer_hash[tmp.shift[3..-1].to_i] = tmp.shift while tmp[0] } } 

# ### Long string using string.split (shorter benchmark) 
# => 0.690000 0.000000 0.690000 ( 0.693698) 


puts Benchmark.measure {1000.times {ids, answers = *s.scan(/(?<=ID:)(\d+)_([^_]+)/).transpose } } 

# ### Long string using string.scan Regexp (shorter benchmark) 
# => 0.900000 0.000000 0.900000 ( 0.901358) 
+1

lol ... Regexes по своей сути медленнее. Они медленны, когда вы много отступаете. Здесь не будет никакого возврата, потому что 'ID:' и '_' устанавливают четкие границы, на которых * ids * и * ответы * начинаются и заканчиваются. Как вы могли видеть в тестах с большим вводом, нет ничего асимптотически различного между регулярными выражениями и нерепрессивными решениями. Просто постоянные операции в регексовом решении требуют немного более подготовительного времени. Вы не должны позволять микро-оптимизации запускать ваш код. Кроме того, OP говорит, что он имеет дело с * длинной строкой *. – ndn

+1

@ndn - Приятно знать :-) ... Наверное, вы правы. Обычно я допускаю, чтобы микрооптимизация выполняла мой код только тогда, когда код собирается снова и снова запускаться внутри циклов (например, когда он часто используется в механизме синтаксического анализа). Если код не повторяется так часто, я обычно выбираю более четкий код. Машины становятся все сильнее, а «более быстрый код» не всегда означает «лучший код». – Myst

+0

Также я обновил мое регулярное выражение, так как ему действительно не нужно было искать часть 'ID:' и удалять ручную распаковку. Я считаю, что тесты для короткой строки на вашей машине должны дать вам где-то около ** 0.470000 **. – ndn

1

Без регулярных выражений, мое предложение:

i = 0 
names = [] 
ids = [] 
s = "ID:1_Answer1_ID:2_Answer2_ID:3_AnswerRandom_ID:789_Answer3.5" 

s.split("_").each do |f| 
    if i.odd? 
     names.push(f) 
    else 
     ids.push(f.split(":")[1])  
    end 
    i+=1 
end 
0

Там много способы сделать это. Вот тот, который использует два последовательных split и без регулярных выражений. Я предположил, что строка начинается ID:, так как потребуется дополнительная спецификация проблемы, если это не обязательно.

ids, answers = s[3..-1].split(/_ID:/).map { |str| str.split('_') }.transpose 
    #=> [["1", "2", "3", "789"], 
    # ["Answer1", "Answer2", "AnswerRandom", "Answer3.5"]] 

шаги:

t = s[3..-1] 
    #=> "1_Answer1_ID:2_Answer2_ID:3_AnswerRandom_ID:789_Answer3.5" 
a = t.split('_ID:') 
    #=> ["1_Answer1", "2_Answer2", "3_AnswerRandom", "789_Answer3.5"] 
b = a.map { |str| str.split('_') } 
    #=> [["1", "Answer1"], ["2", "Answer2"], 
    # ["3", "AnswerRandom"], ["789", "Answer3.5"]] 
b.transpose 
    #=> [["1", "2", "3", "789"], 
    # ["Answer1", "Answer2", "AnswerRandom", "Answer3.5"]] 
Смежные вопросы