【问题标题】:How do I split text into key-value pairs?如何将文本拆分为键值对?
【发布时间】:2012-01-18 08:20:18
【问题描述】:

我正在构建一个脚本来读取和解析 Ruby 中的 markdown 文件。该脚本需要能够读取和理解文件顶部的 multimarkdown 标头信息,以便它可以对输出执行其他操作。

标头值如下所示:

Title: My Treatise on Kumquats
Author: Joe Schmoe
Author URL: http://somedudeswebsite.me/
Host URL: http://googlesnewthing.com/
Created: 2012-01-01 09:41

我不知道如何将文本行拆分为一个简单的键值字典。在这种情况下,内置的拆分功能似乎不起作用,因为我只希望它在每行中第一次出现冒号 (:) 时拆分。额外的冒号将成为值字符串的一部分。

如果重要的话,我在 OS X 上使用 Ruby 1.8.7。

【问题讨论】:

    标签: ruby string parsing


    【解决方案1】:

    这样做:

    s = <<EOS
    Title: My Treatise on Kumquats
    Author: Joe Schmoe
    Author URL: http://somedudeswebsite.me/
    Host URL: http://googlesnewthing.com/
    Created: 2012-01-01 09:41
    EOS
    
    h = Hash[s.each_line.map { |l| l.chomp.split(': ', 2) }]
    p h
    

    输出:

    {"Title"=>"My Treatise on Kumquats", "Author"=>"Joe Schmoe", "Author URL"=>"http://somedudeswebsite.me/", "Host URL"=>"http://googlesnewthing.com/", "Created"=>"2012-01-01 09:41"}
    

    【讨论】:

    • 您可能希望在 ': ' 上进行拆分,或者以其他方式去除尾随空格。
    • @SergioTulentsev:很公平。
    【解决方案2】:

    split 与可选的第二个参数一起使用(感谢@MichaelKohl)

    s = 'Author URL: http://somedudeswebsite.me/'
    key, value = s.split ': ', 2
    puts key
    puts value
    

    输出

    Author URL
    http://somedudeswebsite.me/
    

    【讨论】:

    • 除非我会丢失 URL 中的冒号并且它不再是有效的 URL。
    • 看起来是一个相当优雅的解决方案,我想我会接受它。为了以防万一,我会把这个问题留到早上。 :)
    • 可能永远都会有,但我认为 Multimarkdown 引擎只有冒号,所以我想保持这种兼容性——尽管我承认这个选项从来没有想过。
    • @SergioTulentsev: split 有一个可选的第二个参数,用于指定拆分后所需的最大零件数:"'Author URL: http://somedudeswebsite.me/'".split(':', 2) #=&gt; ["'Author URL", " http://somedudeswebsite.me/'"]
    • @MichaelKohl:谢谢,没用过。更新了答案。
    【解决方案3】:

    您可以使用正则表达式来解析您的文本:

    str = "Title: My Treatise on Kumquats
    Author: Joe Schmoe
    Author URL: http://somedudeswebsite.me/
    Host URL: http://googlesnewthing.com/
    Created: 2012-01-01 09:41"
    
    matches = str.scan /^(.+?): (.+?)$/m
    
    matches.each { |m|
       key = m[0]
       value = m[1]
    }
    

    这是多行正则表达式 (/&lt;regex&gt;/m) - 它将每行匹配成两组(索引为 0 和 1)。第一组将包含第一次出现": "(冒号+空格)之前的所有字符。第二组将包含此行中的所有其余字符(直到正则表达式遇到行尾 $)。

    这是将结果转换为哈希的方法:

    dictionary = matches.inject({}) do |dict, m| 
      dict[m[0]] = m[1]
      dict
    end
    

    更新

    正如 Michael Kohl 所提到的,可以将其写成一行:

    hash = Hash[str.scan /^(.+?): (.+?)$/m]
    

    【讨论】:

      【解决方案4】:

      你可以这样做

      >> s = 'Author URL: http://somedudeswebsite.me/'
      >> first_idx = s.index(':')
      >> key,value = s[0..first_idx-1],s[first_idx+1..s.length]
      => ["Author URL", " http://somedudeswebsite.me/"]
      

      或通过键值散列

      >> kv = Hash[*s[0..first_idx-1],s[first_idx+1..s.length]]
      => {"Author URL"=>" http://somedudeswebsite.me/"}
      

      希望对你有帮助

      【讨论】:

        【解决方案5】:

        line.split(':',2)是你想要的吗?

        String#split 接受指定要拆分的部分的第二个参数。 它适用于 ruby​​ 1.9.3,在早期版本中不确定。 (但我几乎可以肯定它也适用于 1.9.2)

        如果这不可用,line.scan(%r{^([^:]*):(.*)}) 也应该可以工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多