src/mojijs/Japanese.js
/**
* The script is part of MojiJS.
*
* AUTHOR:
* natade (http://twitter.com/natadea)
*
* LICENSE:
* The MIT license https://opensource.org/licenses/MIT
*/
import Unicode from "./Unicode.js";
/**
* 日本語の変換を扱うクラス
*/
export default class Japanese {
/**
* カタカナをひらがなに変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toHiragana(text) {
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
return(String.fromCharCode(ch.charCodeAt(0) - 0x0060));
};
return (text.replace(/[\u30A1-\u30F6]/g, func));
}
/**
* ひらがなをカタカナに変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toKatakana(text) {
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
return(String.fromCharCode(ch.charCodeAt(0) + 0x0060));
};
return (text.replace(/[\u3041-\u3096]/g, func));
}
/**
* スペースを半角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toHalfWidthSpace(text) {
return (text.replace(/\u3000/g, String.fromCharCode(0x0020)));
}
/**
* スペースを全角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toFullWidthSpace(text) {
return (text.replace(/\u0020/g, String.fromCharCode(0x3000)));
}
/**
* 英数記号を半角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toHalfWidthAsciiCode(text) {
let out = text;
out = out.replace(/\u3000/g, "\u0020"); //全角スペース
out = out.replace(/[\u2018-\u201B]/g, "\u0027"); //シングルクォーテーション
out = out.replace(/[\u201C-\u201F]/g, "\u0022"); //ダブルクォーテーション
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
const code = ch.charCodeAt(0);
return (String.fromCharCode(code - 0xFEE0));
};
return (out.replace(/[\uFF01-\uFF5E]/g, func));
}
/**
* 英数記号を全角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toFullWidthAsciiCode(text) {
let out = text;
out = out.replace(/\u0020/g, "\u3000"); //全角スペース
out = out.replace(/\u0022/g, "\u201D"); //ダブルクォーテーション
out = out.replace(/\u0027/g, "\u2019"); //アポストロフィー
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
const code = ch.charCodeAt(0);
return (String.fromCharCode(code + 0xFEE0));
};
return (out.replace(/[\u0020-\u007E]/g, func));
}
/**
* アルファベットを半角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toHalfWidthAlphabet(text) {
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
return (String.fromCharCode(ch.charCodeAt(0) - 0xFEE0));
};
return (text.replace(/[\uFF21-\uFF3A\uFF41-\uFF5A]/g, func));
}
/**
* アルファベットを全角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toFullWidthAlphabet(text) {
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
return (String.fromCharCode(ch.charCodeAt(0) + 0xFEE0));
};
return (text.replace(/[A-Za-z]/g, func));
}
/**
* 数値を半角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toHalfWidthNumber(text) {
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
return(String.fromCharCode(ch.charCodeAt(0) - 0xFEE0));
};
return (text.replace(/[\uFF10-\uFF19]/g, func));
}
/**
* 数値を全角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toFullWidthNumber(text) {
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
return(String.fromCharCode(ch.charCodeAt(0) + 0xFEE0));
};
return (text.replace(/[0-9]/g, func));
}
/**
* カタカナを半角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toHalfWidthKana(text) {
/**
* @type {Object<number, string>}
* @private
*/
const map = {
0x3001 : "\uFF64" , // 、
0x3002 : "\uFF61" , // 。 。
0x300C : "\uFF62" , // 「 「
0x300D : "\uFF63" , // 」 」
0x309B : "\uFF9E" , // ゛ ゙
0x309C : "\uFF9F" , // ゜ ゚
0x30A1 : "\uFF67" , // ァ ァ
0x30A2 : "\uFF71" , // ア ア
0x30A3 : "\uFF68" , // ィ ィ
0x30A4 : "\uFF72" , // イ イ
0x30A5 : "\uFF69" , // ゥ ゥ
0x30A6 : "\uFF73" , // ウ ウ
0x30A7 : "\uFF6A" , // ェ ェ
0x30A8 : "\uFF74" , // エ エ
0x30A9 : "\uFF6B" , // ォ ォ
0x30AA : "\uFF75" , // オ オ
0x30AB : "\uFF76" , // カ カ
0x30AC : "\uFF76\uFF9E" , // ガ ガ
0x30AD : "\uFF77" , // キ キ
0x30AE : "\uFF77\uFF9E" , // ギ ギ
0x30AF : "\uFF78" , // ク ク
0x30B0 : "\uFF78\uFF9E" , // グ グ
0x30B1 : "\uFF79" , // ケ ケ
0x30B2 : "\uFF79\uFF9E" , // ゲ ゲ
0x30B3 : "\uFF7A" , // コ コ
0x30B4 : "\uFF7A\uFF9E" , // ゴ ゴ
0x30B5 : "\uFF7B" , // サ サ
0x30B6 : "\uFF7B\uFF9E" , // ザ ザ
0x30B7 : "\uFF7C" , // シ シ
0x30B8 : "\uFF7C\uFF9E" , // ジ ジ
0x30B9 : "\uFF7D" , // ス ス
0x30BA : "\uFF7D\uFF9E" , // ズ ズ
0x30BB : "\uFF7E" , // セ セ
0x30BC : "\uFF7E\uFF9E" , // ゼ ゼ
0x30BD : "\uFF7F" , // ソ ソ
0x30BE : "\uFF7F\uFF9E" , // ゾ ゾ
0x30BF : "\uFF80" , // タ タ
0x30C0 : "\uFF80\uFF9E" , // ダ ダ
0x30C1 : "\uFF81" , // チ チ
0x30C2 : "\uFF81\uFF9E" , // ヂ ヂ
0x30C3 : "\uFF6F" , // ッ ッ
0x30C4 : "\uFF82" , // ツ ツ
0x30C5 : "\uFF82\uFF9E" , // ヅ ヅ
0x30C6 : "\uFF83" , // テ テ
0x30C7 : "\uFF83\uFF9E" , // デ デ
0x30C8 : "\uFF84" , // ト ト
0x30C9 : "\uFF84\uFF9E" , // ド ド
0x30CA : "\uFF85" , // ナ ナ
0x30CB : "\uFF86" , // ニ ニ
0x30CC : "\uFF87" , // ヌ ヌ
0x30CD : "\uFF88" , // ネ ネ
0x30CE : "\uFF89" , // ノ ノ
0x30CF : "\uFF8A" , // ハ ハ
0x30D0 : "\uFF8A\uFF9E" , // バ バ
0x30D1 : "\uFF8A\uFF9F" , // パ パ
0x30D2 : "\uFF8B" , // ヒ ヒ
0x30D3 : "\uFF8B\uFF9E" , // ビ ビ
0x30D4 : "\uFF8B\uFF9F" , // ピ ピ
0x30D5 : "\uFF8C" , // フ フ
0x30D6 : "\uFF8C\uFF9E" , // ブ ブ
0x30D7 : "\uFF8C\uFF9F" , // プ プ
0x30D8 : "\uFF8D" , // ヘ ヘ
0x30D9 : "\uFF8D\uFF9E" , // ベ ベ
0x30DA : "\uFF8D\uFF9F" , // ペ ペ
0x30DB : "\uFF8E" , // ホ ホ
0x30DC : "\uFF8E\uFF9E" , // ボ ボ
0x30DD : "\uFF8E\uFF9F" , // ポ ポ
0x30DE : "\uFF8F" , // マ マ
0x30DF : "\uFF90" , // ミ ミ
0x30E0 : "\uFF91" , // ム ム
0x30E1 : "\uFF92" , // メ メ
0x30E2 : "\uFF93" , // モ モ
0x30E3 : "\uFF6C" , // ャ ャ
0x30E4 : "\uFF94" , // ヤ ヤ
0x30E5 : "\uFF6D" , // ュ ュ
0x30E6 : "\uFF95" , // ユ ユ
0x30E7 : "\uFF6E" , // ョ ョ
0x30E8 : "\uFF96" , // ヨ ヨ
0x30E9 : "\uFF97" , // ラ ラ
0x30EA : "\uFF98" , // リ リ
0x30EB : "\uFF99" , // ル ル
0x30EC : "\uFF9A" , // レ レ
0x30ED : "\uFF9B" , // ロ ロ
0x30EE : "\uFF9C" , // ヮ ワ
0x30EF : "\uFF9C" , // ワ ワ
0x30F0 : "\uFF72" , // ヰ イ
0x30F1 : "\uFF74" , // ヱ エ
0x30F2 : "\uFF66" , // ヲ ヲ
0x30F3 : "\uFF9D" , // ン ン
0x30F4 : "\uFF73\uFF9E" , // ヴ ヴ
0x30F5 : "\uFF76" , // ヵ カ
0x30F6 : "\uFF79" , // ヶ ケ
0x30F7 : "\uFF9C\uFF9E" , // ヷ ヷ
0x30F8 : "\uFF72\uFF9E" , // ヸ イ゙
0x30F9 : "\uFF74\uFF9E" , // ヹ エ゙
0x30FA : "\uFF66\uFF9E" , // ヺ ヺ
0x30FB : "\uFF65" , // ・ ・
0x30FC : "\uFF70" // ー ー
};
/**
* @param {string} ch
* @private
*/
const func = function(ch) {
if(ch.length === 1) {
return(map[ch.charCodeAt(0)]);
}
else {
return(map[ch.charCodeAt(0)] + map[ch.charCodeAt(1)]);
}
};
return (text.replace(/[\u3001\u3002\u300C\u300D\u309B\u309C\u30A1-\u30FC][\u309B\u309C]?/g, func));
}
/**
* カタカナを全角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toFullWidthKana(text) {
/**
* @type {Object<number, number>}
* @private
*/
const map = {
0xFF61 : 0x3002 , // 。 。
0xFF62 : 0x300C , // 「 「
0xFF63 : 0x300D , // 」 」
0xFF64 : 0x3001 , // 、
0xFF65 : 0x30FB , // ・ ・
0xFF66 : 0x30F2 , // ヲ ヲ
0xFF67 : 0x30A1 , // ァ ァ
0xFF68 : 0x30A3 , // ィ ィ
0xFF69 : 0x30A5 , // ゥ ゥ
0xFF6A : 0x30A7 , // ェ ェ
0xFF6B : 0x30A9 , // ォ ォ
0xFF6C : 0x30E3 , // ャ ャ
0xFF6D : 0x30E5 , // ュ ュ
0xFF6E : 0x30E7 , // ョ ョ
0xFF6F : 0x30C3 , // ッ ッ
0xFF70 : 0x30FC , // ー ー
0xFF71 : 0x30A2 , // ア ア
0xFF72 : 0x30A4 , // イ イ
0xFF73 : 0x30A6 , // ウ ウ
0xFF74 : 0x30A8 , // エ エ
0xFF75 : 0x30AA , // オ オ
0xFF76 : 0x30AB , // カ カ
0xFF77 : 0x30AD , // キ キ
0xFF78 : 0x30AF , // ク ク
0xFF79 : 0x30B1 , // ケ ケ
0xFF7A : 0x30B3 , // コ コ
0xFF7B : 0x30B5 , // サ サ
0xFF7C : 0x30B7 , // シ シ
0xFF7D : 0x30B9 , // ス ス
0xFF7E : 0x30BB , // セ セ
0xFF7F : 0x30BD , // ソ ソ
0xFF80 : 0x30BF , // タ タ
0xFF81 : 0x30C1 , // チ チ
0xFF82 : 0x30C4 , // ツ ツ
0xFF83 : 0x30C6 , // テ テ
0xFF84 : 0x30C8 , // ト ト
0xFF85 : 0x30CA , // ナ ナ
0xFF86 : 0x30CB , // ニ ニ
0xFF87 : 0x30CC , // ヌ ヌ
0xFF88 : 0x30CD , // ネ ネ
0xFF89 : 0x30CE , // ノ ノ
0xFF8A : 0x30CF , // ハ ハ
0xFF8B : 0x30D2 , // ヒ ヒ
0xFF8C : 0x30D5 , // フ フ
0xFF8D : 0x30D8 , // ヘ ヘ
0xFF8E : 0x30DB , // ホ ホ
0xFF8F : 0x30DE , // マ マ
0xFF90 : 0x30DF , // ミ ミ
0xFF91 : 0x30E0 , // ム ム
0xFF92 : 0x30E1 , // メ メ
0xFF93 : 0x30E2 , // モ モ
0xFF94 : 0x30E4 , // ヤ ヤ
0xFF95 : 0x30E6 , // ユ ユ
0xFF96 : 0x30E8 , // ヨ ヨ
0xFF97 : 0x30E9 , // ラ ラ
0xFF98 : 0x30EA , // リ リ
0xFF99 : 0x30EB , // ル ル
0xFF9A : 0x30EC , // レ レ
0xFF9B : 0x30ED , // ロ ロ
0xFF9C : 0x30EF , // ワ ワ
0xFF9D : 0x30F3 , // ン ン
0xFF9E : 0x309B , // ゛ ゙
0xFF9F : 0x309C // ゜ ゚
};
/**
* @param {string} str
* @private
*/
const func = function(str) {
if(str.length === 1) {
return (String.fromCharCode(map[str.charCodeAt(0)]));
}
else {
const next = str.charCodeAt(1);
const ch = str.charCodeAt(0);
if(next === 0xFF9E) {
// Shift-JISにない濁点(ヷ、ヸ、ヹ、ヺ)は意図的に無視
// ヴ
if (ch === 0xFF73) {
return (String.fromCharCode(0x3094));
}
// ガ-ド、バ-ボ
else if(
((0xFF76 <= ch) && (ch <= 0xFF84)) ||
((0xFF8A <= ch) && (ch <= 0xFF8E)) ) {
return (String.fromCharCode(map[ch] + 1));
}
}
// 半濁点
else if(next === 0xFF9F) {
// パ-ポ
if((0xFF8A <= ch) && (ch <= 0xFF8E)) {
return (String.fromCharCode(map[ch] + 2));
}
}
return (String.fromCharCode(map[ch]) + String.fromCharCode(map[next]));
}
};
return (text.replace(/[\uFF61-\uFF9F][\uFF9E\uFF9F]?/g, func));
}
/**
* 半角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toHalfWidth(text) {
return Japanese.toHalfWidthKana(Japanese.toHalfWidthAsciiCode(text));
}
/**
* 全角に変換
* @param {String} text - 変換したいテキスト
* @returns {String} 変換後のテキスト
*/
static toFullWidth(text) {
return Japanese.toFullWidthKana(Japanese.toFullWidthAsciiCode(text));
}
/**
* 指定したテキストの横幅を半角/全角でカウント
* - 半角を1、全角を2としてカウント
* - 半角は、ASCII文字、半角カタカナ。全角はそれ以外とします。
* @param {String} text - カウントしたいテキスト
* @returns {Number} 文字の横幅
*/
static getWidth(text) {
const utf32_array = Unicode.toUTF32Array(text);
let count = 0;
for(let i = 0; i < utf32_array.length; i++) {
const ch = utf32_array[i];
if((ch < 0x80) || ((0xFF61 <= ch) && (ch < 0xFFA0))) {
count++;
}
else {
count += 2;
}
}
return count;
}
/**
* 指定したテキストの横幅を半角/全角で換算した場合の切り出し
* - 半角を1、全角を2としてカウント
* - 半角は、ASCII文字、半角カタカナ。全角はそれ以外とします。
* @param {String} text - 切り出したいテキスト
* @param {Number} offset - 切り出し位置
* @param {Number} size - 切り出す長さ
* @returns {String} 切り出したテキスト
*/
static cutTextForWidth(text, offset, size) {
const utf32_array = Unicode.toUTF32Array(text);
const SPACE = 0x20 ; // ' '
const output = [];
let is_target = false;
let position = 0;
let cut_size = size;
let ioffset = offset;
if(ioffset < 0) {
cut_size += ioffset;
ioffset = 0;
}
if(cut_size <= 0) {
return "";
}
for(let i = 0; i < utf32_array.length; i++) {
const ch = utf32_array[i];
const ch_size = ((ch < 0x80) || ((0xFF61 <= ch) && (ch < 0xFFA0))) ? 1 : 2;
if(position >= ioffset) {
is_target = true;
if(cut_size >= ch_size) {
output.push(ch);
}
else {
output.push(SPACE);
}
cut_size -= ch_size;
if(cut_size <= 0) {
break;
}
}
position += ch_size;
// 2バイト文字の途中をoffset指定していた場合になる。
if(((position - 1) >= ioffset) && !is_target) {
cut_size--;
output.push(SPACE);
}
}
return Unicode.fromUTF32Array(output);
}
}