# Convert Persian and Arabic digits to English

I use the following utility method to convert Persian and Arabic digits to English using regex:

convertNumbers2English: function (string) {
return string.replace(/[٠١٢٣٤٥٦٧٨٩]/g, function (c) {
return c.charCodeAt(0) - 1632;
}).replace(/[۰۱۲۳۴۵۶۷۸۹]/g, function (c) {
return c.charCodeAt(0) - 1776;
});
}

• first one is for Arabic digits and the second one is for Persian. – Ali Sherafat Jun 27 '17 at 11:53
• Nope! thy are almost similar, ٤٥٦!= ۴۵۶ look precisely :) and also they have different character code. – Ali Sherafat Jun 27 '17 at 11:55
• I searched(CTRL + F) for [٠١٢٣٤٥٦٧٨٩] characters in this page and it matches both. Proof – Tushar Jun 27 '17 at 11:59
• @Proof It only matches the first string for me. – Graipher Jun 27 '17 at 12:01
• @yuri, in Chrome 58 it matches both for me, but if I search for [0123456789] in this page it also matches both. It's a question of browsers trying to be helpful. – Peter Taylor Jun 27 '17 at 14:07

## 3 Answers

Be nice to the maintenance programmer, even (especially?) if you expect it to be you. If you're mixing characters which are visually indistinguishable but don't need to be literal self-representations, you can use Unicode escapes and hexadecimal offsets as so:

convertNumbers2English: function (string) {
return string.replace(/[\u0660-\u0669]/g, function (c) {
return c.charCodeAt(0) - 0x0660;
}).replace(/[\u06f0-\u06f9]/g, function (c) {
return c.charCodeAt(0) - 0x06f0;
});
}


Just that small change accomplishes the following:

1. I can easily see that I haven't missed any digits without having to count;
2. I can easily see that I haven't accidentally mixed digits from the two styles;
3. I can easily see that the offset subtracted is correct in each case;
4. I can easily see that the values returned by the anonymous functions are integers from 0 to 9 and not strings or codepoints corresponding to '0' to '9', which is useful if I'm not primarily a JS developer;
5. If I care about squeezing every last byte out of my JS, I can see a way to combine the two into one:

convertNumbers2English: function (string) {
return string.replace(/[\u0660-\u0669\u06f0-\u06f9]/g, function (c) {
return c.charCodeAt(0) & 0xf;
});
}


The minimiser should take care of unescaping the Unicode escapes.

6. It might be slightly easier for me to find which characters they are, because I can look up the hex values in a Unicode character table.
• Just out of curiosity, why do you say that the characters don't need to be literal self-representations? Wouldn't it be more meaningful to use the self-representation? – Kodos Johnson Jun 27 '17 at 19:26
• @KodosJohnson, is ٩ the Persian one or the Arabic one? Is \u06f5 the Persian one or the Arabic one? I hope that answers your question. – Peter Taylor Jun 27 '17 at 20:07

You can use capture groups

return string.replace(/([٠١٢٣٤٥٦٧٨٩])|([۰۱۲۳۴۵۶۷۸۹])/g, function(m, $1,$2) {
return m.charCodeAt(0) - ($1 ? 1632 : 1776); });  $1 is the character matched by [٠١٢٣٤٥٦٧٨٩] and $2 is character matched by [۰۱۲۳۴۵۶۷۸۹]. Using ternary operator, correct value is subtracted from the charcode. If arrow function is supported by target environments, the code can be shortened to convertNumbers2English: str => str.replace(/([٠١٢٣٤٥٦٧٨٩])|([۰۱۲۳۴۵۶۷۸۹])/g, (m,$1, $2) => m.charCodeAt(0) - ($1 ? 1632 : 1776));


If the string may contain both "Arabic" and "Persian" numbers then a one-line "replace" can do the job as follows.

The Arabic and Persian numbers are converted to English equivalents. Other text characters remain unchanged.

Num= "۳٣۶٦۵any٥۵٤۶32٠۰";     // Output should be "33665any55453200"

Num = Num.replace(/[٠-٩]/g, d => "٠١٢٣٤٥٦٧٨٩".indexOf(d)).replace(/[۰-۹]/g, d => "۰۱۲۳۴۵۶۷۸۹".indexOf(d));

console.log(Num);