Skip to content

Instantly share code, notes, and snippets.

@rummelonp
Last active August 29, 2015 14:05
Show Gist options
  • Save rummelonp/c9c06ff53822b6f69725 to your computer and use it in GitHub Desktop.
Save rummelonp/c9c06ff53822b6f69725 to your computer and use it in GitHub Desktop.
Parslet で漢数字を Int にするやつ
require 'parslet'
module Kansuji
NUMBERS = %w{一 二 三 四 五 六 七 八 九}
DIGITS = %w{十 百 千}
UNITS = %w{万 億 兆 京 垓 𥝱 穣 溝 澗 正 載 極 恒河沙 阿僧祇 那由他 不可思議 無量大数}
def self.parser
@parser ||= Parser.new
end
def self.transform
@transform ||= Transform.new
end
def self.parse(text)
transform.apply(
parser.parse(
text
)
)
end
class Parser < Parslet::Parser
root(:expressions)
rule(:expressions) {
(
expression >> unit.maybe >> expressions.maybe |
expression
).as(:expressions)
}
rule(:expression) {
(
number.maybe >> digit >> expression.maybe |
number
).as(:expression)
}
rule(:number) {
alternative_str(NUMBERS).as(:number)
}
rule(:digit) {
alternative_str(DIGITS).as(:digit)
}
rule(:unit) {
alternative_str(UNITS).as(:unit)
}
def alternative_str(values)
values.map { |value|
str(value)
}.reduce { |alternatives, parslet|
alternatives | parslet
}
end
end
class Transform < Parslet::Transform
rule(expressions: simple(:expressions)) {
expressions
}
rule(expression: simple(:expression)) {
expression
}
rule(number: simple(:number)) {
Number.new(number).to_i
}
rule(digit: simple(:digit)) {
Digit.new(digit).to_i
}
rule(number: simple(:number), digit: simple(:digit)) {
Number.new(number).to_i * Digit.new(digit).to_i
}
rule(digit: simple(:digit), expression: simple(:expression)) {
Digit.new(digit).to_i + expression
}
rule(number: simple(:number), digit: simple(:digit), expression: simple(:expression)) {
Number.new(number).to_i * Digit.new(digit).to_i + expression
}
rule(expression: simple(:expression), unit: simple(:unit), expressions: simple(:expressions)) {
expression * Unit.new(unit).to_i + expressions
}
end
class Number < Struct.new(:number)
def to_i
NUMBERS.index(number) + 1
end
end
class Digit < Struct.new(:digit)
def to_i
10 ** (DIGITS.index(digit) + 1)
end
end
class Unit < Struct.new(:unit)
def to_i
10_000 ** (UNITS.index(unit) + 1)
end
end
end
@rummelonp
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment