追記・いろいろ機能追加したアラビア数字から漢数字に変換する関数をパッケージ化してGithubに上げた
Rで{zipnagu}
というパッケージのkansuji2arabic
という関数を使うとアラビア数字が漢数字になる。
そこで逆に、アラビア数字を漢数字に変換するには……と考えてみた。すでに既存のいい関数があるかもしれないとは思うが見つけられなかった。
アラビア数字を一文字一文字漢数字に置き換えるもの(1234なら一二三四となる)と、9999までの範囲で1234なら千二百三十四と変換するものを考えた。
追記: 1万以上に対応できる要因改良した
自作関数
依存関係は{tidyverse}
がインストールされて入れば解決される。
具体的には{magrittr}
と{stringr}
がインストールされていると大丈夫。
library("magrittr") arabic2kansuji <- function(num, zero = c("〇", "零")){ zero <- match.arg(zero) arabicn <- "1234567890" if(zero == "〇") kansuji <- "一二三四五六七八九〇" else if(zero == "零") kansuji <- "一二三四五六七八九零" arabicn <- stringr::str_split(arabicn, "") %>% unlist() kansuji <- stringr::str_split(kansuji, "") %>% unlist() names(kansuji) <- arabicn num %>% stringr::str_replace_all(kansuji) } arabic2kansuji_num <- function(num){ n <- stringr::str_split(num, stringr::boundary(type = "character")) %>% purrr::reduce(c) %>% as.numeric() if(length(n) >= 5) warning("too long to convert.") m <- max(which(n >= 0)) - which(n >= 0) + 1 names(n) <- m for(i in 1:length(n)){ if(as.numeric(names(n[i])) %% 4 == 1){ if(n[i] >= 1) n[i] <- arabic2kansuji(n[i]) } else if(as.numeric(names(n[i])) %% 4 == 2){ if(n[i] >= 2) n[i] <- paste0(arabic2kansuji(n[i]), "十") else if(n[i] == 1) n[i] <- "十" } else if(as.numeric(names(n[i])) %% 4 == 3){ if(n[i] >= 2) n[i] <- paste0(arabic2kansuji(n[i]), "百") else if(n[i] == 1) n[i] <- "百" } else if(as.numeric(names(n[i])) %% 4 == 0){ if(n[i] >= 2) n[i] <- paste0(arabic2kansuji(n[i]), "千") else if(n[i] == 1) n[i] <- "千" } n <- gsub("0", NA, n) stringr::str_flatten(na.omit(n)) }
自作関数について、arabic2kansuji
は
Rで文字列中の旧字体を新字体にまとめて変換する - Qiita
を参考にほぼ流用した。
arabic2kansuji_num
は{zipnagu}
のkansuji2arabic_all
を参考にした。
使ってみる
arabic2kansuji
は単純に数字を漢数字に置き換えるだけ。
> arabic2kansuji(1234) [1] "一二三四"
と返す。
漢数字以外を含んでいてもその部分は保持される。
> arabic2kansuji("1989年は1月7日までが昭和64年です") [1] "一九八九年は一月七日までが昭和六四年です" > arabic2kansuji("東京都新宿区西新宿2丁目8−1") [1] "東京都新宿区西新宿二丁目八−一"
半角数字にしか対応していないので、全角は変換されない。
> arabic2kansuji("東京都新宿区西新宿2丁目8−1") [1] "東京都新宿区西新宿2丁目8−1"
デフォルトでは0が〇に変換されるが引数で指定すると零にも変換できる。
> arabic2kansuji("今年は西暦2020年で令和2年です") [1] "今年は西暦二〇二〇年で令和二年です" arabic2kansuji("今年は西暦2020年で令和2年です", zero = "零") [1] "今年は西暦二零二零年で令和二年です"
単純に一文字一文字置換しているだけなので、2020で二千二十は返せないので、そこはarabic2kansuji_num
で対応(正しい答えを返すのは9999まで、1万以上も入力受け付けるが正しい答えを返さない)。
arabic2kansuji_num
は数字しか受け付けない。
> arabic2kansuji_num(2020) [1] "二千二十" > arabic2kansuji_num(2020年) エラー: 想定外のシンボルです in "arabic2kansuji_num(2020年" > arabic2kansuji_num("2020年") if (as.numeric(names(n[i]))%%4 == 1) { でエラー: TRUE/FALSE が必要なところが欠損値です 追加情報: 警告メッセージ: 1: function_list[[k]](value) で: 強制変換により NA が生成されました 2: arabic2kansuji_num("2020年") で: too long to convert
1万以上を入力すると万とか億とかが入ってこないので正しい答えを返せない(今後の課題、アイディアはありそれができそうなコードを組んでいるが実装できていない)。
> arabic2kansuji_num(123456789) [1] "一二千三百四十五六千七百八十九" 警告メッセージ: arabic2kansuji_num(123456789) で: too long to convert
あとarabic2kansuji_num
はループ処理を中でやっているので大量に数字を流し込むとちょっと遅い。
今後の課題
arabic2kansuji_num
で1万以上も対応できるようにしたい。arabic2kansuji_num
で漢数字以外の文字列を保持したまま変換できるようにしたい。- ループ処理じゃない方法でスマートにやりたい。
ざっとこんなところ。