Last active
December 9, 2018 10:03
-
-
Save nimzo6689/e4d55591d71174d428070d4f5b931924 to your computer and use it in GitHub Desktop.
数字の読み方を返すプログラム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function ConvertTo-NumberRuby { | |
[CmdletBinding()] | |
param( | |
[Parameter( | |
Mandatory = $True, | |
ValueFromPipeline = $True, | |
ValueFromPipelineByPropertyName = $True | |
)] | |
[string[]]$Sources | |
) | |
process { | |
foreach ($src in $Sources) { | |
$( | |
for ($digit = $src.Length; $digit -gt 0; $digit--) { | |
$number = [Char]::GetNumericValue($src[$src.Length - $digit]) | |
switch ($number) { | |
0 {} | |
1 { | |
switch ($digit % 4) { | |
1 {'いち'} | |
0 {'いっ'} | |
default {} | |
} | |
} | |
2 { 'に' } | |
3 { 'さん' } | |
4 { 'よん' } | |
5 { 'ご' } | |
6 { | |
if ($digit -band 3 -band 2) {'ろっ'} else {'ろく'} | |
} | |
7 { 'なな' } | |
8 { | |
if ($digit -band 3 -band 2) {'はっ'} else {'はち'} | |
} | |
9 { 'きゅう' } | |
} | |
switch ($digit) { | |
13 { 'ちょう' } | |
9 { 'おく' } | |
5 { 'まん' } | |
{$_ % 4 -eq 0} { | |
if ($number -eq 3) {'ぜん'} else {'せん'} | |
} | |
{$_ % 4 -eq 3} { | |
switch ($number) { | |
3 {'びゃく'} | |
{$_ -in (6, 8)} {'ぴゃく'} | |
default {'ひゃく'} | |
} | |
} | |
{$_ % 4 -eq 2} { "じゅう" } | |
} | |
} | |
) -join '' | |
} | |
} | |
} | |
549832, 418313801, 15056, 10001000 | ConvertTo-NumberRuby |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var NumberRuby = NumberRuby || {}; | |
(function (_) { | |
_.toLargeDigitRuby = function (digit) { | |
if (digit & 3) { | |
return ""; | |
} | |
switch (digit >> 2) { | |
case 0: | |
return ""; | |
case 1: | |
return "まん"; | |
case 2: | |
return "おく"; | |
case 3: | |
return "ちょう"; | |
default: | |
console.error("「京」以降はサポート対象外です。"); | |
} | |
} | |
_.toSmallDigitRuby = function (number, digit) { | |
let _num = Number(number); | |
switch (_num) { | |
case 0: | |
return ""; | |
case 1: | |
switch (digit & 3) { | |
case 1: | |
case 2: | |
return ""; | |
} | |
} | |
switch (digit & 3) { | |
case 0: | |
return ""; | |
case 1: | |
return "じゅう"; | |
case 2: | |
switch (_num) { | |
case 3: | |
return "びゃく"; | |
case 6: | |
case 8: | |
return "ぴゃく"; | |
} | |
return "ひゃく"; | |
break; | |
case 3: | |
if (_num === 3) { | |
return "ぜん"; | |
} | |
return "せん"; | |
} | |
} | |
_.toNumberRuby = function (number, digit) { | |
switch (Number(number)) { | |
case 0: | |
return ""; | |
case 1: | |
switch (digit & 3) { | |
case 1: | |
case 2: | |
return ""; | |
case 3: | |
return "いっ"; | |
} | |
return "いち"; | |
case 2: | |
return "に"; | |
case 3: | |
return "さん"; | |
case 4: | |
return "よん"; | |
case 5: | |
return "ご"; | |
case 6: | |
if (digit & 3 & 2) { | |
return "ろっ"; | |
} | |
return "ろく"; | |
case 7: | |
return "なな"; | |
case 8: | |
if (digit & 3 & 2) { | |
return "はっ"; | |
} | |
return "はち"; | |
case 9: | |
return "きゅう"; | |
} | |
} | |
_.from = function (numbers) { | |
return ('' + numbers).split('') | |
.reverse() | |
.map((value, index) => _.toNumberRuby(value, index) | |
+ _.toSmallDigitRuby(value, index) + _.toLargeDigitRuby(index)) | |
.reverse() | |
.join(''); | |
} | |
} | |
)(NumberRuby); | |
console.log(NumberRuby.from(58095165)); | |
console.log(NumberRuby.from(418313801)); | |
console.log(NumberRuby.from(15056)); | |
console.log(NumberRuby.from(10001000)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.qiita.nimzo6689; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.function.BiFunction; | |
import java.util.function.Function; | |
import java.util.stream.Stream; | |
/** | |
* 数字の送り仮名を返す。<br> | |
* 対象となる数字:1~1京未満までの自然数 | |
* | |
* @see 数字の読み方について<br> | |
* https://www.coscom.co.jp/learnjapanese101/wordcategory/basicwords_numbers-c.html | |
* @author nimzo6689 | |
*/ | |
public class NumberReading { | |
private final long source; | |
private SmallDigitReader smallDigitReader; | |
private LargeDigitReader largeDigitReader; | |
public NumberReading(long source) { | |
this.source = source; | |
this.smallDigitReader = SmallDigitReader.ONES; | |
} | |
public static void main(String[] args) { | |
Stream.of(58_095_165L, 800_418_313_801L, 15_056L, 10_001_000L) | |
.map(v -> String.format("%,d", v) + "=" + new NumberReading(v).say()) | |
.forEach(System.out::println); | |
} | |
public String say() { | |
final StringBuilder ansBuilder = new StringBuilder(); | |
long unreadSource = source; | |
for (int i = 0; i < String.valueOf(source).length(); i++) { | |
// まだ読み方を取得していない数列の一番右にある数字を取得。 | |
NumberReader numberReader = NumberReader.of((int) (unreadSource % 10)); | |
// 読み方を取得 | |
if (i % 4 == 0) { | |
largeDigitReader = largeDigitReader == null | |
? LargeDigitReader.NONE : largeDigitReader.increment(); | |
ansBuilder.insert(0, largeDigitReader.say()); | |
} | |
ansBuilder.insert(0, smallDigitReader.say(numberReader)); | |
ansBuilder.insert(0, numberReader.say(smallDigitReader, largeDigitReader)); | |
// インクリメント | |
smallDigitReader = smallDigitReader.rotate(); | |
unreadSource = unreadSource / 10; | |
} | |
return ansBuilder.toString(); | |
} | |
private enum LargeDigitReader { | |
NONE(""), | |
MAN("まん"), | |
OKU("おく"), | |
CHO("ちょう"),; | |
// 「京」以降は省略。 | |
private final String reading; | |
private LargeDigitReader(String reading) { | |
this.reading = reading; | |
} | |
public String say() { | |
return reading; | |
} | |
public final LargeDigitReader increment() { | |
if (LargeDigitReader.values().length == ordinal() + 1) { | |
throw new IllegalStateException("「京」以降の桁はサポート対象外です。"); | |
} | |
return LargeDigitReader.values()[ordinal() + 1]; | |
} | |
} | |
private enum SmallDigitReader { | |
ONES(""), | |
TENS("じゅう"), | |
HUNDREDS(n -> { | |
switch (n) { | |
case THREE: | |
return "びゃく"; | |
case SIX: | |
case EIGHT: | |
return "ぴゃく"; | |
default: | |
return "ひゃく"; | |
} | |
}), | |
THOUSANDS(n -> n == NumberReader.THREE ? "ぜん" : "せん"),; | |
private final Function<NumberReader, String> reader; | |
private SmallDigitReader(Function<NumberReader, String> reader) { | |
this.reader = reader; | |
} | |
private SmallDigitReader(String reading) { | |
this((n) -> reading); | |
} | |
public String say(NumberReader number) { | |
return number == NumberReader.ZERO ? "" : reader.apply(number); | |
} | |
// 「一」→「十」→「百」→「千」→「一」→... | |
public final SmallDigitReader rotate() { | |
return SmallDigitReader.values().length == ordinal() + 1 | |
? ONES : SmallDigitReader.values()[ordinal() + 1]; | |
} | |
} | |
private enum NumberReader { | |
ZERO(0, ""), | |
ONE(1, (s, l) -> { | |
switch (s) { | |
case TENS: | |
case HUNDREDS: | |
return ""; | |
case THOUSANDS: | |
return "いっ"; | |
default: | |
return l == LargeDigitReader.CHO | |
? "いっ" : "いち"; | |
} | |
}), | |
TWO(2, "に"), | |
THREE(3, "さん"), | |
FOUR(4, "よん"), | |
FIVE(5, "ご"), | |
SIX(6, (s, l) -> s == SmallDigitReader.HUNDREDS ? "ろっ" : "ろく"), | |
SEVEN(7, "なな"), | |
EIGHT(8, (s, l) | |
-> (s == SmallDigitReader.HUNDREDS || s == SmallDigitReader.THOUSANDS) | |
|| (l == LargeDigitReader.CHO && s == SmallDigitReader.ONES) | |
? "はっ" : "はち" | |
), | |
NINE(9, "きゅう"),; | |
private static final Map<Integer, NumberReader> VALUES; | |
static { | |
VALUES = Arrays.stream(NumberReader.values()).collect( | |
Collectors.toMap(d -> d.number, d -> d) | |
); | |
} | |
private final int number; | |
private final BiFunction<SmallDigitReader, LargeDigitReader, String> reader; | |
private NumberReader(int number, BiFunction<SmallDigitReader, LargeDigitReader, String> reader) { | |
this.number = number; | |
this.reader = reader; | |
} | |
private NumberReader(int number, String reading) { | |
this(number, (s, l) -> reading); | |
} | |
public static final NumberReader of(int value) { | |
if (VALUES.containsKey(value)) { | |
return VALUES.get(value); | |
} | |
throw new IllegalArgumentException( | |
"Type:" + value + " is not a valid " + NumberReader.class.getName() + " value."); | |
} | |
public String say(SmallDigitReader smallDigit, LargeDigitReader largeDigit) { | |
return reader.apply(smallDigit, largeDigit); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# 数字の読み方について | |
# https://www.coscom.co.jp/learnjapanese101/wordcategory/basicwords_numbers-c.html | |
function read_number() { | |
local readonly SOURCES=$( | |
if [ -p /dev/stdin ]; then cat -; else echo "$@"; fi | |
) | |
for source in ${SOURCES[@]}; do | |
echo $source \ | |
| sed 's/[0-9]/&\n/g' \ | |
| tac \ | |
| grep '[0-9]' \ | |
| sed -e '5s/.*/&まん/' -e '9s/.*/&おく/' -e '13s/.*/&ちょう/' \ | |
| sed -e '2~4s/.*/&じゅう/' \ | |
| sed -e '3~4s/.*/&ひゃく/' -e 's/3ひゃく/3びゃく/' -e 's/6ひゃく/6ぴゃく/' -e 's/8ひゃく/8ぴゃく/' \ | |
| sed -e '4~4s/.*/&せん/' -e 's/3せん/3ぜん/' \ | |
| sed -e 's/0.*\(まん\|おく\|ちょう\)/\1/' -e 's/0.*//' \ | |
| sed -e 's/1/いち/' -e '2~4s/いち.*//' -e '3~4s/いち.*//' -e '4~4s/いち/いっ/' -e '9s/いち/いっ/' \ | |
| sed -e 's/2/に/' \ | |
| sed -e 's/3/さん/' \ | |
| sed -e 's/4/よん/' \ | |
| sed -e 's/5/ご/' \ | |
| sed -e 's/6/ろく/' -e '3~4s/ろく/ろっ/' \ | |
| sed -e 's/7/なな/' \ | |
| sed -e 's/8/はち/' -e '3~4s/はち/はっ/' -e '4~4s/はち/はっ/' \ | |
| sed -e 's/9/きゅう/' \ | |
| tac \ | |
| paste -sd'\0' | |
done | |
} | |
cat << EOF | read_number | |
58095165 | |
418313801 | |
15056 | |
10001000 | |
EOF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- PostgreSQL9.2以降ではSQL関数でも引数に名前を指定できますが、便宜上$nスタイルを使用してます。 | |
CREATE OR REPLACE FUNCTION numerical_to_reading(integer) RETURNS varchar AS $$ | |
-- 数字の読み方を出力する。 | |
WITH RECURSIVE | |
-- 数字の読み方を定義 | |
-- 参考: https://www.coscom.co.jp/learnjapanese101/wordcategory/basicwords_numbers-c.html | |
numeral_reading(numeral, reading) AS ( | |
VALUES | |
(0, ''), | |
(1, 'いち'), (2, 'に'), (3, 'さん'), | |
(4, 'よん'), (5, 'ご'), (6, 'ろく'), | |
(7, 'なな'), (8, 'はち'), (9, 'きゅう') | |
), | |
-- 1桁ごとの読み方を定義(一、十、百、千) | |
small_digit(digit, reading) AS ( | |
VALUES | |
(0, ''), -- 一の位の数については呼称なし。 | |
(1, 'じゅう'), (2, 'ひゃく'), (3, 'せん') | |
), | |
-- 例外的な数字の読み方 | |
patch_small_digit_numeral(digit, numeral, reading) AS ( | |
VALUES | |
(1, 1, ''), (2, 1, ''), (3, 1, 'いっ'), -- 十、百、千(いっせん)の読み方を定義 | |
(2, 6, 'ろっ'), -- 6百(ろっぴゃく)の読み方を定義 | |
(2, 8, 'はっ'), (3, 8, 'はっ') -- 8百(はっせん)、8千(はっせん)の読み方を定義 | |
), | |
-- 例外的な桁の読み方 | |
patch_small_digit(digit, numeral, reading) AS ( | |
VALUES | |
(1, 0, ''), (2, 0, ''), (3, 0, ''), -- 0の場合は十百千は読まない | |
(2, 3, 'びゃく'), (3, 3, 'ぜん'), -- 3百(さんびゃく)、3千(さんぜん)の読み方を定義 | |
(2, 6, 'ぴゃく'), (2, 8, 'ぴゃく') -- 6百(ろっぴゃく)、8百(はっぴゃく)の読み方を定義 | |
), | |
-- 4桁区切りの桁ごとの読み方を定義(万、億、兆、...) | |
large_digit(digit, reading) AS ( | |
VALUES | |
(4, 'まん'), (8, 'おく') -- 「兆」以降は省略。 | |
), | |
-- args.numeralに指定された数字を桁ごとに分割する。 | |
digit_numeral_mapping(digit, numeral) AS ( | |
SELECT | |
0, | |
substring( | |
abs($1)::varchar from char_length(abs($1)::varchar) for 1 | |
)::integer | |
UNION ALL | |
SELECT | |
dnm.digit + 1, | |
substring( | |
abs($1)::varchar from char_length(abs($1)::varchar) - (dnm.digit + 1) for 1 | |
)::integer | |
FROM digit_numeral_mapping AS dnm | |
WHERE dnm.digit < char_length(abs($1)::varchar) - 1 | |
), | |
-- 桁ごとに数字の読み方を出力する。 | |
readings_per_digit(digit, reading) AS ( | |
SELECT | |
dnm.digit, | |
COALESCE(psdn.reading, nr.reading) -- 0~9までの数字 | |
|| COALESCE(psd.reading, sd.reading) -- 十百千の位 | |
|| COALESCE(ld.reading, '') -- 万、億の位 | |
FROM digit_numeral_mapping AS dnm | |
NATURAL JOIN numeral_reading AS nr | |
JOIN small_digit AS sd | |
ON sd.digit = dnm.digit % 4 | |
LEFT JOIN large_digit AS ld | |
ON ld.digit = dnm.digit | |
LEFT JOIN patch_small_digit_numeral AS psdn | |
ON psdn.digit = dnm.digit % 4 | |
AND psdn.numeral = dnm.numeral | |
LEFT JOIN patch_small_digit AS psd | |
ON psd.digit = dnm.digit % 4 | |
AND psd.numeral = dnm.numeral | |
ORDER BY dnm.digit DESC | |
) | |
-- 数字の読み方を出力 | |
SELECT | |
CASE | |
WHEN $1 = 0 THEN 'ぜろ' | |
WHEN $1 < 0 THEN 'まいなす' | |
ELSE '' | |
END || array_to_string(array_agg(reading ORDER BY digit DESC), '') AS reading | |
FROM readings_per_digit | |
; | |
$$ LANGUAGE SQL | |
IMMUTABLE | |
RETURNS NULL ON NULL INPUT; | |
VALUES | |
(0, numerical_to_reading(0)), | |
(-15056, numerical_to_reading(-15056)), | |
(10001000, numerical_to_reading(10001000)), | |
(58095165, numerical_to_reading(58095165)), | |
(418313801, numerical_to_reading(418313801)) | |
; | |
-- 0 "ぜろ" | |
-- -15056 "まいなすいちまんごせんごじゅうろく" | |
-- 10001000 "いっせんまんいっせん" | |
-- 58095165 "ごせんはっぴゃくきゅうまんごせんひゃくろくじゅうご" | |
-- 418313801 "よんおくいっせんはっぴゃくさんじゅういちまんさんぜんはっぴゃくいち" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- ※PL/pgSQLです。 | |
CREATE OR REPLACE FUNCTION numerical_to_reading(numerical_value integer) RETURNS varchar AS $$ | |
DECLARE | |
numerical_char CONSTANT varchar := abs(numerical_value)::varchar; | |
numerical_length CONSTANT integer := char_length(numerical_char); | |
digit integer; | |
currval integer; | |
ret varchar := ''; | |
BEGIN | |
IF numerical_value = 0 THEN | |
-- 一桁の0の場合のみ「ぜろ」が読まれるため、すぐにRETURNで返す。 | |
RETURN 'ぜろ'; | |
ELSIF numerical_value < 0 THEN | |
-- マイナス符号の読み方を定義 | |
ret := ret || 'まいなす'; | |
END IF; | |
-- 整数部の読み方を求める | |
FOR i IN 1 .. numerical_length LOOP | |
digit := numerical_length - i + 1; | |
currval := substring(numerical_char FROM i FOR 1)::integer; | |
-- 数字の読み方を逐次解釈 | |
-- 参考: https://www.coscom.co.jp/learnjapanese101/wordcategory/basicwords_numbers-c.html | |
CASE currval | |
WHEN 1 THEN | |
CASE digit % 4 | |
WHEN 0 THEN | |
-- 1,000(いっせん)の読み方を定義 | |
ret := ret || 'いっ'; | |
WHEN 1 THEN | |
ret := ret || 'いち'; | |
ELSE | |
-- 10, 100の場合は1自体は読まない。 | |
NULL; | |
END CASE; | |
WHEN 2 THEN | |
ret := ret || 'に'; | |
WHEN 3 THEN | |
ret := ret || 'さん'; | |
WHEN 4 THEN | |
ret := ret || 'よん'; | |
WHEN 5 THEN | |
ret := ret || 'ご'; | |
WHEN 6 THEN | |
IF digit % 4 = 3 THEN | |
-- 6百(ろっぴゃく)の読み方を定義 | |
ret := ret || 'ろっ'; | |
ELSE | |
ret := ret || 'ろく'; | |
END IF; | |
WHEN 7 THEN | |
ret := ret || 'なな'; | |
WHEN 8 THEN | |
IF digit % 4 IN (3, 0) THEN | |
-- 8百(はっせん)、8千(はっせん)の読み方を定義 | |
ret := ret || 'はっ'; | |
ELSE | |
ret := ret || 'はち'; | |
END IF; | |
WHEN 9 THEN | |
ret := ret || 'きゅう'; | |
ELSE | |
NULL; | |
END CASE; | |
-- 1桁ごとの読み方を定義(一、十、百、千) | |
IF currval = 0 THEN | |
NULL; | |
ELSE | |
CASE digit % 4 | |
WHEN 2 THEN | |
ret := ret || 'じゅう'; | |
WHEN 3 THEN | |
IF currval = 3 THEN | |
-- 3百(さんびゃく)の読み方を定義 | |
ret := ret || 'びゃく'; | |
ELSIF currval IN (6, 8) THEN | |
-- 6百(ろっぴゃく)、8百(はっぴゃく)の読み方を定義 | |
ret := ret || 'ぴゃく'; | |
ELSE | |
ret := ret || 'ひゃく'; | |
END IF; | |
WHEN 0 THEN | |
IF currval = 3 THEN | |
-- 3千(さんぜん)の読み方を定義 | |
ret := ret || 'ぜん'; | |
ELSE | |
ret := ret || 'せん'; | |
END IF; | |
ELSE | |
NULL; | |
END CASE; | |
END IF; | |
-- 4桁ごとにつく単位の読み方を定義(万、億)※兆以降はサポート対象外 | |
CASE digit | |
WHEN 5 THEN | |
ret := ret || 'まん'; | |
WHEN 9 THEN | |
ret := ret || 'おく'; | |
ELSE | |
NULL; | |
END CASE; | |
END LOOP; | |
RETURN ret; | |
END | |
$$ LANGUAGE plpgsql | |
IMMUTABLE | |
RETURNS NULL ON NULL INPUT; | |
VALUES | |
(0, numerical_to_reading(0)), | |
(-15056, numerical_to_reading(-15056)), | |
(10001000, numerical_to_reading(10001000)), | |
(58095165, numerical_to_reading(58095165)), | |
(418313801, numerical_to_reading(418313801)) | |
; | |
-- 0 "ぜろ" | |
-- -15056 "まいなすいちまんごせんごじゅうろく" | |
-- 10001000 "いっせんまんいっせん" | |
-- 58095165 "ごせんはっぴゃくきゅうまんごせんひゃくろくじゅうご" | |
-- 418313801 "よんおくいっせんはっぴゃくさんじゅういちまんさんぜんはっぴゃくいち" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment