2015-08-08 89 views
0

我很努力从iOS应用发送的字符串中提取ID和Answer值。在以下示例中,我有四个ID和四个Answers需要提取。从长字符串中提取值

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. IDSID前面: - ID:
  2. 实际IDS是数字 - (\d+)
  3. 他们分开从回答带下划线 - _
  4. 答案本身的非下划线字符([^_]+)

String#scan与一对阵列[id, answer]的返回的数组的序列,因此,我们转置它来获得两个数组 - 一个与IDS和一个与答案。然后我们使用多个分配将解压外部数组。

+0

很好的解决方案,并很好的解释。 –

+0

非常干净的解决方案。非常感谢! – rak

+0

但它不会捕获空白答案值。例如,问题1没有任何答案。 s =“ID:1__ID:2_Answer2_ID:3_AnswerRandom_ID:789_Answer3.5” – rak

-1

请澄清一下您的问题。

ID和答案需要匹配吗?他们总是成对吗? "_"字符是否始终用作分隔符(这意味着答案应该被编码)?总是格式:

"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"] 

编辑

我使用正则表达式爱@ NDN的答案......这是清晰的,但可能会更短字符串会比较慢。

这里是我的机器上的基准 - 它们表明,在性能上的差异主要表现为较短的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

大声笑...正则表达式本质上并不慢。当你做很多回溯时,它们很慢。在这里,不会有任何回溯,因为'ID:'和'_'在* id *和* answers *开始和结束的位置设置了明确的界限。正如您在基准测试中看到的那样,输入数据量更大,正则表达式和非正则表达式解决方案之间没有任何渐进性差异。正则表达式解决方案中的常量操作需要更多的准备时间。你不应该让微优化运行你的代码。 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"]]