16
\$\begingroup\$

I use the following code to convert ۱۲۳۴۵ to ‍12345, effectively transliterating the persian numbers into latin numbers:

String.prototype.toEnglishDigits = function () {
        var num_dic = {
            '۰': '0',
            '۱': '1',
            '۲': '2',
            '۳': '3',
            '۴': '4',
            '۵': '5',
            '۶': '6',
            '۷': '7',
            '۸': '8',
            '۹': '9',
        }

        return parseInt(this.replace(/[۰-۹]/g, function (w) {
            return num_dic[w]
        }));
    }

console.log('۱۲۳۴۵'.toEnglishDigits());
\$\endgroup\$
2
  • \$\begingroup\$ Does javascript have something like python's str.translate? \$\endgroup\$
    – o11c
    Commented Jul 16, 2015 at 20:50
  • \$\begingroup\$ See this stackoverflow post. \$\endgroup\$
    – Mahozad
    Commented Dec 24, 2021 at 15:05

2 Answers 2

13
\$\begingroup\$

Instead of using a map, you can get the corresponding digits directly by subtracting the character code of '۰'. That is, since the character code of '۳' is 1779 and the character code of '۰' is 1776, you can calculate that:

'۳'.charCodeAt(0) - '۰'.charCodeAt(0) = 1779 - 1776 = 3

Using the above logic, the function can be written shorter:

String.prototype.toEnglishDigits = function () {
    var charCodeZero = '۰'.charCodeAt(0);
    return parseInt(this.replace(/[۰-۹]/g, function (w) {
        return w.charCodeAt(0) - charCodeZero;
    }));
}
\$\endgroup\$
1
  • \$\begingroup\$ Of course this assumes that the codes for the characters for both roman and persian numerals are sequential. Though this is a logical and desirable feature of an encoding, it is not guaranteed. \$\endgroup\$ Commented Jul 17, 2015 at 13:59
9
\$\begingroup\$

Patching core prototypes like String to add non-standard functionality is considered bad software engineering practice, especially in a language where code from various libraries may need to coexist on the same webpage. I'd just define a regular function.

There's nothing "English" about the output. The result is a Number. It's not even in base 10. Really, this is an enhancement to parseInt(), and should be named accordingly.

Interestingly, the inverse operation is built-in to many browsers (notably not WebKit):

(12345).toLocaleString('fa')      # => "۱۲۳۴۵"

What you are trying to do, though, has no built-in browser support. However, note that the problem is not unique to Persian numerals — many other languages in that part of the world have positional base-10 numeral systems. Therefore, I suggest a generalization:

var PERSIAN_NUMERALS = '۰'.charCodeAt(0);

function numeralParseInt(zero, str) {
    var digits = new Array(str.length);
    for (var i = 0; i < str.length; i++) {
        digits[i] = str.charCodeAt(i);
        if (zero <= digits[i] && digits[i] < zero + 10) {
            digits[i] -= zero - 48;     // '0' = ASCII 48
        }
    }
    return String.fromCharCode.apply(null, digits);
}

function persianParseInt(str) {
    return numeralParseInt(PERSIAN_NUMERALS, str);
}
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.