2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ScalaのfoldRight練習として、漢数字を含む文字列から数値に変換する関数を作成してみました

Posted at

はじめに

業務で、漢数字を含む文字列を数値に変換する処理が必要になりました。昔Javaで実装した処理はScala、Pythonをかじり始めた今見返すと残念でしかなく、チョロっと調べた範囲でもあまりScalaっぽいサンプルも見つからず。
なので、foldRightの練習も兼ねて関数を作成してみました。ScalaやPythonは半年くらいの片手間実装経験しかないので、そもそも人のコードも自分のコードもScalaっぽい、とか言える程の理解も腕前もありませんが。。。

結論

先に結論ですが、foldRight便利!
あとScalaもやっぱり便利!
昔々Javaで書いたロジックに比べてとても簡潔になりました。
Scalaっぽい気がする!

文字定義

数値文字、桁文字を以下の通りマップで定義します。以上の桁はLongを超えてしまうのでとりあえず桁はここまでです。BigDecimalって何桁いけるのかわかりませんが、仮にScalaの数値桁が対応しており、恒河沙みたいな複数文字で表現される桁文字列にも対応したい場合は、マップのキーを桁文字(Char)ではなく、桁文字列(String)にすればいいのかな?まぁ実用上問題ないからこのままでいいかな、と。

// 数値文字 -> 値マップ
private val numericCharacterMap = Map(
  '0' -> 0,
  '0' -> 0,
  '零' -> 0,
  '〇' -> 0,
  '1' -> 1,
  '1' -> 1,
  '一' -> 1,
  '壱' -> 1,
  '2' -> 2,
  '2' -> 2,
  '二' -> 2,
  '弐' -> 2,
  '3' -> 3,
  '3' -> 3,
  '三' -> 3,
  '参' -> 3,
  '4' -> 4,
  '4' -> 4,
  '四' -> 4,
  '5' -> 5,
  '5' -> 5,
  '五' -> 5,
  '6' -> 6,
  '6' -> 6,
  '六' -> 6,
  '7' -> 7,
  '7' -> 7,
  '七' -> 7,
  '8' -> 8,
  '8' -> 8,
  '八' -> 8,
  '9' -> 9,
  '9' -> 9,
  '九' -> 9,
)
// 桁文字 -> 桁マップ
private val digitMap = Map(
  '十' -> 1,
  '百' -> 2,
  '千' -> 3,
  '万' -> 4,
  '萬' -> 4,
  '億' -> 8,
  '兆' -> 12,
  '京' -> 16,
)

文字列 -> 数値変換関数

こんな感じになりました。

def convertFromKanjiToNumber(input: String): Long = {
  // 定義に無い文字は捨てる(桁区切り文字等)
  var tmp = input.filter(x => numericCharacterMap.contains(x) || digitMap.contains(x))
  // 桁文字(十、万等)の前に数値文字が無い場合”1”を追加(”百十”を”1百1十”に)
  tmp = tmp.head + tmp
  tmp = tmp.sliding(2).map(x => {
    if (digitMap.contains(x(0)) && digitMap.contains(x(1)) && (digitMap(x(0)) >= digitMap(x(1))))
      "1" + x(1)
    else
      x(1)
  }).mkString("")
  // foldRightで下位の文字から数値に変換して足し込む
  // 初期値は値、桁(十百千の桁)、桁(万以上の桁)のtuple)
  val result = tmp.foldRight((0L, 0, 0)){ (x, current) =>
    // 桁文字の場合、桁の繰り上げ
    if (digitMap.contains(x))
      (current._1, if (digitMap(x) > 3) 0 else digitMap(x), if (digitMap(x) > 3) digitMap(x) else current._3)
    // 数値文字の場合、桁を適用して足し込み
    else
      (current._1 + numericCharacterMap(x) * Math.pow(10, current._2 + current._3).toLong, current._2 + 1, current._3)
  }
  result._1
}

テストデータ

以下はとりあえず正しく変換できました

val testDataList = List(
  ("一", 1),
  ("十四", 14),
  ("二十三", 23),
  ("四十", 40),
  ("千六", 1006),
  ("一二三", 123),
  ("千十", 1010),
  ("5千二百", 5200),
  ("5千万", 5000 * 10000),
  ("百十萬", 100 * 10000 + 10 * 10000),
  ("十二万", 120 * 1000),
  ("7千五十億百七五", 7000L * 10000L * 10000L + 50L * 10000L * 10000L + 175L)
)
2
1
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?