What's the solution and the right way to convert digits in JavaScript?

109 Views Asked by At

following all qa about converting digits in javascript in Stackoverflow. However, I had a problem/ question

method one


        // Convert Persian and Arabic digits to English using the new function
        var convertedValue = convertDigitsToEnglish(currentPhoneValue);

    // Function to convert Persian and Arabic digits to English digits
    function convertDigitsToEnglish(value) {
        var persianDigits = '۰۱۲۳۴۵۶۷۸۹';
        var arabicDigits = '٠١٢٣٤٥٦٧٨٩';
        var englishDigits = '0123456789';

        for (var i = 0; i < 10; i++) {
            value = value.replace(new RegExp(persianDigits[i], 'g'), englishDigits[i]);
            value = value.replace(new RegExp(arabicDigits[i], 'g'), englishDigits[i]);
        }

        return value;
    }

enter image description here

method two


        // Convert Persian and Arabic digits to English
        var convertedValue = convert_number.toNormal(phoneField.val());

var convert_number = (function () {
    var numerals = {
        persian: ["۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"],
        arabic: ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"]
    };

    return {
        toNormal: function (str) {
            if (!str) {
                return '';
            }
            var num, i, len = str.length, result = "";

            for (i = 0; i < len; i++) {
                num = numerals["persian"].indexOf(str[i]);
                num = num != -1 ? num : numerals["arabic"].indexOf(str[i]);
                if (num == -1) num = str[i];
                result += num;
            }
            return result;
        }
    }
}

enter image description here

in the method one works only for Persian/Farsi digits! and why doesn't it work correctly at all for the Arabic language? arabic digits numbers ٤٥٦‍ (four five and six) numbers are not converted to English/Latin numbers. we defined this in the code and it shouldn't be a problem and it should work correctly, but it doesn't and these three numbers can't be converted, and doesn't accept these numbers!

in method two. both Persian and Arabic languages converted and no problem with this method.

For better explanations for my question so that nothing is missed. Let's say this is for a mobile number field. I have also specified elsewhere that a keyboard the person cannot enter any additional characters such as asterisk, plus, minus, etc., other than the numbers 0 to 9.

        // Remove non-numeric characters
        var numericPhoneValue = convertedValue.replace(/[^0-9]/g, '');

In order for the Arabic and Persian numbers not to be recognized as foreign, I converted them to English numbers with this (upper convert function). So that the user can enter numbers with English, Farsi, and Arabic numbers. And it doesn't matter what language it is in. Converts to English in any digit. Also, prevents the entry of additional characters.

I also used the pattern solution instead of these (convert), but it is ignored by the browser in different situations, and it is also suitable for English only. And it is not suitable for Persian and Arabic. Was my method correct? Is there a better, shorter and cleaner way? Why the first method does not work correctly for some Arabic numbers? But does the second method work correctly?

2

There are 2 best solutions below

4
Roozbeh Mohammadzadeh On

I think you can use something like this which will work with both Farsi and Arabic numbers

function toEnglishDigits(str) {
  const persianNumbers = ["۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹", "۰"]
  const arabicNumbers = ["١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩", "٠"]
  const englishNumbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]

  return str.split("").map(c => englishNumbers[persianNumbers.indexOf(c)] ||
    englishNumbers[arabicNumbers.indexOf(c)] || c).join("")
}

console.log(toEnglishDigits("۶٦۵any٥32"))

0
3limin4t0r On

Assuming all characters have a unique Unicode value between the different languages you could store them in a single object or Map instance with their decimal counterpart.

const decimalMap = new Map([
  // Persian
  ["۰", "0"],
  ["۱", "1"],
  ["۲", "3"],
  // ...

  // Arabic
  ["٠", "0"],
  // ...
]);

With decimalMap defined translating the characters is as simple as checking if they're present within decimalMap. If a character is not present, keep it as is.

function toEnglishDigits(string) {
  return Array.from(string, char => decimalMap.get(char) ?? char).join("");
}

The above uses Array.from() to split the string into characters (and keep Unicode surrogate pairs intact). We then check the decimalMap for a translation with decimalMap.get(char) if the character is not in the Map instance undefined will be returned. Which in turn causes the ?? operator to return the right hand side of the operator (the original character).

// build the decimal translation map
const decimalMap = new Map();

function addDecimals(decimals) {
  const chars = Array.from(decimals);
  chars.forEach((char, index) => decimalMap.set(char, index.toString()));
}

addDecimals("۰۱۲۳۴۵۶۷۸۹"); // Persian
addDecimals("٠١٢٣٤٥٦٧٨٩"); // Arabic

// string translation
function toEnglishDigits(string) {
  return Array.from(string, char => decimalMap.get(char) ?? char).join("");
}

// snippet event handlers
document.forms["convert-digits"].addEventListener("submit", function (event) {
  event.preventDefault();
  this.elements.output.value = toEnglishDigits(this.elements.input.value);
});

document.getElementById("input-characters").addEventListener("click", function (event) {
  if (event.target.tagName !== "BUTTON") return;
  document.forms["convert-digits"].elements.input.value += event.target.textContent;
});
form {
  margin-bottom: 0.5em;
}

#input-characters label {
  display: inline-block;
  width: 4em;
}

#input-characters button {
  display: inline-block;
  width: 2em;
}
<form id="convert-digits">
  <input name="input" />
  <button>convert</button>
  <input name="output" disabled />
</form>

<div id="input-characters">
  <div>
    <label>Persian</label>
    <button>۰</button>
    <button>۱</button>
    <button>۲</button>
    <button>۳</button>
    <button>۴</button>
    <button>۵</button>
    <button>۶</button>
    <button>۷</button>
    <button>۸</button>
    <button>۹</button>
  </div>

  <div>
    <label>Arabic</label>
    <button>٠</button>
    <button>١</button>
    <button>٢</button>
    <button>٣</button>
    <button>٤</button>
    <button>٥</button>
    <button>٦</button>
    <button>٧</button>
    <button>٨</button>
    <button>٩</button>
  </div>
</div>