桁数の大きな数値のText To Speech(TTS)読み上げのAppleScriptです。
# 日本語環境における枝葉的な(マニアックな)数値表現の仕様に関する話であり、他の言語では関係ない話です。漢字文化圏で使われる数値表現のようですが、たとえば中国や韓国で使われている数値桁表現との間で厳密な互換性があるかといった確認は行なっておりません
実行前に日本語TTS読み上げ音声の「Otoya」あるいは「Kyoko」をインストールしておいてください。
まず、AppleScriptが指数表示なしに表現できる数値は10^9程度で、それを超えると指数表示になります。
ただし、指数表示になった数値を数値文字列に変換するノウハウは全世界的に共有されており、そのためのサブルーチン(Stringify)を呼び出すだけで済みます。
AppleScriptのsayコマンドでは「100兆」までの読み上げはそれっぽく実行してくれますが、「1000兆」になると読み上げ内容が数字の羅列になってしまいます。
これについても、大きな数値を日本語数値エンコーディング文字列に変換するサブルーチンを昔から公開しており(本Blog開設当初の11年前に掲載)、それを呼び出すだけで日本語数値表現文字列に変換できるため、読み上げられることでしょう。
Number | Japanese | English |
1 | 一(いち) | one |
10 | 十(じゅう) | ten |
100 | 百(ひゃく) | hundred |
1000 | 千(せん) | thousand |
10000 | 万(まん) | 10 thousand |
100000 | 十万(じゅうまん) | 100 thousand |
1000000 | 百万(ひゃくまん) | million |
10000000 | 千万(せんまん) | 10 million |
100000000 | 億(おく) | 100million |
1000000000000 | 兆(ちょう) | villion |
1000000000000000 | 京(けい) | thousand villion |
100000000000000000 | 100京(ひゃっけい) | trillion |
10^24 | 丈(じょ) | |
10^28 | 穣(じょう) | |
10^52 | 恒河沙(ごうがしゃ) | |
10^56 | 阿僧祇(あそうぎ) | |
10^60 | 那由他(なゆた) | |
10^64 | 不可思議(ふかしぎ) | |
10^68 | 無量大数(むりょうたいすう) |
とはいえ、「阿僧祇(あそうぎ、10^56)「那由多(なゆた、10^60)」といった数値桁を読み上げさせるとTTSが正しく読み上げてくれません。さすがにこんなにマニアックな数値表現はカバーしなくてよいでしょう。「丈(じょ)」「穣(じょう)」など似た音の桁が存在するあたり、これらは口に出して読み上げるものではなく、文字で読むためだけのものだと強く感じるものです。
AppleScript名:TTSで日本語数値読み上げ |
repeat with i from 0 to 15 set aNum to (10 ^ i) say Stringify(aNum) of me using "Kyoko" –or "Otoya" end repeat on Stringify(x) — for E+ numbers set x to x as string set {tids, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, {"E+"}} if (count (text items of x)) = 1 then set AppleScript’s text item delimiters to {tids} return x else set {n, z} to {text item 1 of x, (text item 2 of x) as integer} set AppleScript’s text item delimiters to {tids} set i to character 1 of n set decSepChar to character 2 of n — "." or "," set d to text 3 thru -1 of n set l to count d if l > z then return (i & (text 1 thru z of d) & decSepChar & (text (z + 1) thru -1 of d)) else repeat (z – l) times set d to d & "0" end repeat return (i & d) end if end if end Stringify |
AppleScript名:TTSで日本語数値読み上げ v2 |
repeat with i from 15 to 70 set aNum to (10 ^ i) set jRes to encodeJapaneseNumText(aNum) of japaneseNumberEncodingKit say jRes using "Kyoko" –or "Otoya" end repeat –課題:オーバーフローチェックを行っていない set a to "102320120000108220010" set jRes to encodeJapaneseNumText(a) of japaneseNumberEncodingKit –> "1垓232京120兆1億822万10" script japaneseNumberEncodingKit –数字文字列を日本語数値表現文字列に変換 on encodeJapaneseNumText(aNum) set aText to Stringify(aNum) of me set aText to aText as Unicode text set dotText to "." as Unicode text set upperDigit to "" set lowerDigit to "" –小数点の処理 if dotText is in aText then set b to offset of dotText in aText set upperDigit to characters 1 thru (b – 1) of aText set upperDigit to upperDigit as Unicode text set lowerDigit to characters b thru -1 of aText set lowerDigit to lowerDigit as Unicode text else set upperDigit to aText end if set scaleList3 to {"", "万", "億", "兆", "京", "垓", "丈", "壌", "溝", "砂", "正", "載", "極", "恒河沙", "阿僧梢", "那由他", "不可思議", "無量大数"} set splitDigit to 4 set nList to splitByDigit(upperDigit, splitDigit) of me set nList to reverse of nList set resText to "" set digCount to 1 repeat with i in nList set b to (contents of i) as number if b is not equal to 0 then set resText to (b as text) & item digCount of scaleList3 & resText end if set digCount to digCount + 1 end repeat return resText & lowerDigit end encodeJapaneseNumText –指定桁数で区切る on splitByDigit(a, splitDigit) set aList to characters of a set aList to reverse of aList log aList set resList to {} set tempT to "" set tempC to 1 repeat with i in aList set tempT to contents of i & tempT if tempC mod splitDigit = 0 then set resList to {tempT} & resList set tempT to "" end if set tempC to tempC + 1 end repeat if tempT is not equal to "" then set resList to {tempT} & resList end if resList end splitByDigit on Stringify(x) — for E+ numbers set x to x as string set {tids, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, {"E+"}} if (count (text items of x)) = 1 then set AppleScript’s text item delimiters to tids return x else set {n, z} to {text item 1 of x, (text item 2 of x) as integer} set AppleScript’s text item delimiters to tids set i to character 1 of n set decSepChar to character 2 of n — "." or "," set d to text 3 thru -1 of n set l to count d if l > z then return (i & (text 1 thru z of d) & decSepChar & (text (z + 1) thru -1 of d)) else repeat (z – l) times set d to d & "0" end repeat return (i & d) end if end if end Stringify end script |