Ruby 有没有优雅的方法区分 ‘几’,‘十几’, ‘几十’, ‘几十几’,然后转换为数字

color_huo · 2014年03月16日 · 最后由 zw963 回复于 2014年08月23日 · 6388 次阅读
      data = /(?<m>.天.*晚)/.match('今天二十晚')

      result = /(?<m>.十.)/.match(data[:m])

      # '几'
      if result.nil?
        result = data[:m]
        nights = Application.config.cn[result[2]]
      elsif result[:m][0] == '天'
        # 十几
        nights = Application.config.cn[result[:m].slice(2)].to_i + 10
      else
        # '几十几'
        if result[:m][2] != '晚'
          nights = Application.config.cn[result[:m].slice(0)].to_i * 10 +
            Application.config.cn[result[:m].slice(2)].to_i
        else
          # '几十'
          nights = Application.config.cn[result[:m].slice(0)].to_i * 10
        end

      end
---------------------
  config.cn = {
      '一' => 1,
      '二' => 2,
      '三' => 3,
      '四' => 4,
      '五' => 5,
      '六' => 6,
      '七' => 7,
      '八' => 8,
      '九' => 9,
      '十' => 10
    }

自己写的一个简单的方法,求教各位,各种优雅的实现。

什么叫“今天二十晚”?

看不懂...

%w(十 一 二  三 四  五 六  七  八  九).index("九")

一行代码

12345.to_s.gsub(/./).each_with_index.map { |number, index| ['零一二三四五六七八九'[number.to_i], '个十百千万'.reverse[index]] }.flatten.join # => "一万二千三百四十五个"

#3 楼 @swordray 他貌似要反向操作...

#4 楼 @etnl

'一万二千三百四十五个'.delete('个十百千万').chars.map { |char| '零一二三四五六七八九'.chars.index(char) }.join.to_i # => 12345

Interpreter pattern

#5 楼 @swordray 思路很赞,不过这样好像不能识别‘十一’和‘二十’,等情况

#7 楼 @color_huo 抱歉写的不是很严谨,欢迎继续改进,甚至做成一个开源项目

#8 楼 @swordray 思路已经给我帮助很大,非常感谢

#10 楼 @shiny 继续上班去了,欢迎改进

2 位数就直接查表就好了吧……

#13 楼 @datty258 想到更简单的写法

'一万二千三百四十五个'.gsub(/./) { |c| '零一二三四五六七八九'.chars.index(c) }.to_i # 12345

很奇怪没有找到这样的 gem,所以刚写了一个: https://github.com/qhwa/chinse_number

require 'chinese_number'

ChineseNumber.trans '今天二十万'
#=> "今天200000"

ChineseNumber.extract "今天二十晚"
#=> [20]

ChineseNumber::Parser.new.parse '二零一四'
#=> 2014

ChineseNumber::Parser.new.parse '一万三千'
#=> 13000

#15 楼 @qhwa 想请教下你的 gem 里面的测试代码的 test 方法是 rspec 里面自带的吗?还是你自己写的

#17 楼 @glz1992 自己写的,在最下面定义的

#18 楼 @qhwa 学习了。话说还有一个疑问就是看一些开源项目里有些 module 的定义里面有一行 extend self。不懂这句用什么用?望指教,谢谢。

#19 楼 @glz1992 明白 extend 就明白 extend self 了,建议看一下《Ruby 元编程》,我尝试解释一下

extend 是一个快捷方式:

module B
  def foo; "bar"; end
end

module A
   extend B
end

A.foo
#=> "bar"
# 等效于
...
module A
  class << self
    include B
  end
end

A.foo
#=> "bar"

可以看到, extend 是向类的 singleton class 里面引入模块。 extend self 就是往自己的 singleton class 里面引入自己

module B
  def foo; "bar"; end
end

# 以下几个版本是一致的:

# Version 0
module B
  def self.foo
    "bar"
  end
end

# Version 1
module B
  extend self
end

# Version 2
module B
  class << self
    include B
  end
end
# -------------------

B.foo
#=> "bar"

extend self 就是一种简写再简写

#20 楼 @qhwa 十分感谢。可以可以理解为把 module 里面先前定义的方法定义为它自己的单例方法。那这些方法是不是就只能 module 自己能用,如果一个 class A include 了这个 module,A 不能调用这些方法,但是 A 的实例可以调用这些方法。

#14 楼 @swordray 我在 1.8.7 测试不通过

很有意思的需求。

给一个 丑陋 的实现。

require 'minitest/autorun'
require 'minitest/pride'

describe "应该替换为正确的数字" do
  specify { "这个数字是三十".convert_to_number.must_equal '这个数字是30' }
  specify { "五, 是一个数字".convert_to_number.must_equal '5, 是1个数字' }
  specify { "这是十三".convert_to_number.must_equal '这是13' }
  specify { "返回三十五".convert_to_number.must_equal '返回35' }
end


class String
  def convert_to_number
    hash_map = Hash.new {|h,k| h[k] = k }
    hash_map.merge!({
        '一' => 1,
        '二' => 2,
        '三' => 3,
        '四' => 4,
        '五' => 5,
        '六' => 6,
        '七' => 7,
        '八' => 8,
        '九' => 9,
        '零' => 0,
      })

    gsub(/(?u)\w/,hash_map).gsub(/(?<=\d)十(?=\d)/, '').gsub(/十(?=\d)/, '1').gsub(/(?<=\d)十/, '0')
  end
end
需要 登录 后方可回复, 如果你还没有账号请 注册新账号