当前位置:  开发笔记 > 后端 > 正文

如何在Ruby中对此字符串进行标记?

如何解决《如何在Ruby中对此字符串进行标记?》经验,为你挑选了2个好方法。

我有这个字符串:

%{Children^10 Health "sanitation management"^5}

我想将其转换为将其标记为哈希数组:

[{:keywords=>"children", :boost=>10}, {:keywords=>"health", :boost=>nil}, {:keywords=>"sanitation management", :boost=>5}]

我知道StringScanner和Syntax gem,但我找不到足够的代码示例.

有什么指针吗?



1> rampion..:

对于一个真实的语言,一个词法分析器是要走的路 - 就像Guss说的那样.但是如果完整语言只是像你的例子一样复杂,你可以使用这个快速黑客:

irb> text = %{Children^10 Health "sanitation management"^5}
irb> text.scan(/(?:(\w+)|"((?:\\.|[^\\"])*)")(?:\^(\d+))?/).map do |word,phrase,boost|
       { :keywords => (word || phrase).downcase, :boost => (boost.nil? ? nil : boost.to_i) }
     end
#=> [{:boost=>10, :keywords=>"children"}, {:boost=>nil, :keywords=>"health"}, {:boost=>5, :keywords=>"sanitation management"}]

如果您正在尝试解析常规语言,那么这种方法就足够了 - 尽管使语言不规则并不会带来更多复杂性.

正则表达式的快速细分:

\w+ 匹配任何单项关键字

(?:\\.|[^\\"]])*使用非捕获括号((?:...))来匹配转义双引号字符串的内容-无论是一个转义符(\n,\",\\等)或任何单个字符,这不是一个转义符号或最终报价.

"((?:\\.|[^\\"]])*)" 仅捕获引用的关键字词组的内容.

(?:(\w+)|"((?:\\.|[^\\"])*)")匹配任何关键字 - 单个术语或短语,将单个术语捕获到$1短语内容中$2

\d+ 匹配一个数字.

\^(\d+)捕获插入符号后的数字(^).由于这是第三组捕获括号,因此它将被限制$3.

(?:\^(\d+))? 如果它在那里,则在一个插入符后面捕获一个数字,否则匹配空字符串.

String#scan(regex)尽可能多地将正则表达式与字符串匹配,输出"匹配"数组.如果正则表达式包含捕获的parens,则"匹配"是捕获的项目数组 - 因此$1变为match[0],$2变为match[1]等.任何未与字符串的一部分匹配的捕获括号将映射到nil生成的"匹配"中的条目.

#map随后采取这些比赛中,使用了一些魔法块,打破每个捕捉到的术语不同的变量(我们可以做do |match| ; word,phrase,boost = *match),然后创建您想要的哈希值.完全是其中之一wordphrase将是nil,因为两者都不能与输入匹配,所以(word || phrase)将返回非nil一个,#downcase并将其转换为全小写. boost.to_i将字符串转换为整数,同时(boost.nil? ? nil : boost.to_i)确保nil提升保持不变nil.



2> Aaron Hinni..:

这是一个非强大的例子StringScanner.这是我刚刚从Ruby Quiz改编的代码:Parsing JSON,它有一个很好的解释.

require 'strscan'

def test_parse
  text = %{Children^10 Health "sanitation management"^5}
  expected = [{:keywords=>"children", :boost=>10}, {:keywords=>"health", :boost=>nil}, {:keywords=>"sanitation management", :boost=>5}]


  assert_equal(expected, parse(text))
end

def parse(text)
  @input = StringScanner.new(text)

  output = []

  while keyword = parse_string || parse_quoted_string
    output << {
      :keywords => keyword,
      :boost => parse_boost
    }
    trim_space
  end

  output
end

def parse_string
  if @input.scan(/\w+/)
    @input.matched.downcase
  else
    nil
  end
end

def parse_quoted_string
  if @input.scan(/"/)
    str = parse_quoted_contents
    @input.scan(/"/) or raise "unclosed string"
    str
  else
    nil
  end
end

def parse_quoted_contents
  @input.scan(/[^\\"]+/) and @input.matched
end

def parse_boost
  if @input.scan(/\^/)
    boost = @input.scan(/\d+/)
    raise 'missing boost value' if boost.nil?
    boost.to_i
  else
    nil
  end
end

def trim_space
  @input.scan(/\s+/)
end

推荐阅读
mobiledu2402851323
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有