JavaScript
関数型プログラミング

JavaScriptの関数再帰呼び出しで数字をカンマ区切りにする

More than 1 year has passed since last update.

JavaScriptの関数再帰呼び出しで、文字列の数字に3桁ごとのカンマ区切りを入れてみます。

1234567890 => 1,234,567,890

文字列の数字を引数に渡した関数の再帰呼び出しでカンマ区切りにする

引数はカンマが加えられるように、文字列の数字とします(引数は次項で制限を緩めます)。まず、下3桁をカンマで区切る関数(insertSeparator())を考えましょう。String.substr()メソッドは、文字列から引数で指定した部分を取り出します。第1引数ははじめのインデックス、第2引数が文字数です。負の第1引数は終わりから位置を数え、第2引数を省くと最後までとなります。なお、コードはECMAScript 6にもとづきます(定数宣言constを用いました)。

function insertSeparator(number_string) {
    const length = number_string.length;
    const before = number_string.substr(0, length - 3);
    const after = number_string.substr(-3);
    return before + ',' + after;
}
console.log(insertSeparator('1234567890'));  // 1234567,890

さらに、上の桁もカンマで区切るために、関数を再帰呼び出しします。

// return before + ',' + after;
return insertSeparator(before) + ',' + after;

ただし、このままでは再帰呼び出しがいつまでも終わりません。終了もしくは継続条件を加えて、再帰を止めます。

function insertSeparator(number_string) {
    const length = number_string.length;
    if (length > 3) {  // 継続条件
        const before = number_string.substr(0, length - 3);
        const after = number_string.substr(-3);
        return insertSeparator(before) + ',' + after;
    } else {  // 終了
        return number_string;
    }
}
console.log(insertSeparator('1234567890'));  // 1,234,567,890

引数をラッパー関数で検証する

関数を使いまわそうとすると、わざわざ引数を文字列にしなくても、数値のままでも扱えるようにしたくなります。また、文字列で渡された引数に数字以外が入っていないかも気になるでしょう。そうした引数の確認は、再帰の関数に含めたら、呼び出しのたびに繰り返されて無駄です。

呼び出す再帰関数をラッパーで包んで確かめるのがよいでしょう。今回は、ラッパーを関数(validateStringNumber())でつくってみます。関数を引数に渡したり、関数を戻り値で返すのは、関数型プログラミングで高階関数と呼ばれます。その手法を試してみようということです(ECMAScript 6のアロー関数式=>を用いました)。

function validateStringNumber(func) {  // 関数を引数に渡す
    return (numOrString) => {  // 関数を戻り値で返す
        const number = parseInt(numOrString);
        if (!isNaN(number)) {
            return func(String(number));
        } else {
            return null;
        }
    }
}
function insertSeparator(number_string) {
    const length = number_string.length;
    if (length > 3) {
        const before = number_string.substr(0, length - 3);
        const after = number_string.substr(-3);
        return insertSeparator(before) + ',' + after;
    } else {
        return number_string;
    }
}
const insertComma = validateStringNumber(insertSeparator);

ラッパー関数を試すと、つぎのような結果が得られます。

console.log(insertComma(1234567890));  // 1,234,567,890
console.log(insertComma('123abc'));  // 123
console.log(insertComma('0x123abc'));  // 1,194,684