'Android convert Arabic number to English Number

I get the following error from the gps:

Fatal Exception: java.lang.NumberFormatException
Invalid double: "-٣٣٫٩٣٨٧٤"

Now this is from a error that I got from a user via Fabric. It looks like arabic so I'm guessing it only happens if you have the language set to that, or your sim card? Is it possible to force the gps to send characters in the 0-9 range? Or can I somehow fix this?



Solution 1:[1]

More generic solution using Character.getNumericValue(char)

static String replaceNonstandardDigits(String input) {
    if (input == null || input.isEmpty()) {
        return input;
    }

    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < input.length(); i++) {
        char ch = input.charAt(i);
        if (isNonstandardDigit(ch)) {
            int numericValue = Character.getNumericValue(ch);
            if (numericValue >= 0) {
                builder.append(numericValue);
            }
        } else {
            builder.append(ch);
        }
    }
    return builder.toString();
}

private static boolean isNonstandardDigit(char ch) {
    return Character.isDigit(ch) && !(ch >= '0' && ch <= '9');
}

Solution 2:[2]

A modified generic solution


    fun convertArabic(arabicStr: String): String? {
        val chArr = arabicStr.toCharArray()
        val sb = StringBuilder()
        for (ch in chArr) {
            if (Character.isDigit(ch)) {
                sb.append(Character.getNumericValue(ch))
            }else if (ch == '?'){
                sb.append(".")
            }

            else {
                sb.append(ch)
            }
        }
        return sb.toString()
    }

The second branch is necessary as double numbers has this character as dot separator '?'

Solution 3:[3]

Kotlin developers:

fun ArabicToEnglish(str: String):String {
        var result = ""
        var en = '0'
        for (ch in str) {
            en = ch
            when (ch) {
                '?' -> en = '0'
                '?' -> en = '1'
                '?' -> en = '2'
                '?' -> en = '3'
                '?' -> en = '4'
                '?' -> en = '5'
                '?' -> en = '6'
                '?' -> en = '7'
                '?' -> en = '8'
                '?' -> en = '9'
            }
            result = "${result}$en"
        }
        return result
    }

Solution 4:[4]

This is my code to convert an English number to an Arabic one, the solution could be optimized, modify it according to your needs, it works for all numbers.

fun englishNumberToArabicNumber(number: Int): String {
    val arabicNumber = mutableListOf<String>()
    for (element in number.toString()) {
        when (element) {
            '1' -> arabicNumber.add("?")
            '2' -> arabicNumber.add("?")
            '3' -> arabicNumber.add("?")
            '4' -> arabicNumber.add("?")
            '5' -> arabicNumber.add("?")
            '6' -> arabicNumber.add("?")
            '7' -> arabicNumber.add("?")
            '8' -> arabicNumber.add("?")
            '9' -> arabicNumber.add("?")
            else -> arabicNumber.add("?")
        }
    }
    return arabicNumber.toString()
        .replace("[", "")
        .replace("]", "")
        .replace(",", "")
        .replace(" ", "")


}

Solution 5:[5]

Simple answer

NumberFormat.getInstance(Locale.getDefault()).format(123)

If you want to set for a particular language

NumberFormat.getInstance(Locale.forLanguageTag("ar"))
NumberFormat.getInstance(Locale.ENGLISH)

Solution 6:[6]

Here is another "manual" solution in Kotlin. It might not be the best solution performance-wise.

val number: Double = "??????????".parseToDouble()
/**
 * Parses any valid number string to a [Double].
 * The number can be in Persian/Urdu, Eastern Arabic, or Westerns Arabic numerals.
 * The number can have thousands separators (Persian/Urdu/Eastern Arabic `?` or English `,` or others).
 * The number can be a mix of the above; for example,
 * it can have Persian numerals, [thin space](https://en.wikipedia.org/wiki/Thin_space) `?` as thousands separator, and point `.` as decimal separator.
 *
 * Also see [this Wikipedia article](https://en.wikipedia.org/wiki/Arabic_script_in_Unicode)
 */
fun String.parseToDouble() = this
        .normalizeDigits()
        .normalizeDecimalSeparator()
        .removeOptionalCharacters()
        .toDouble()

/**
 * Converts [Persian/Urdu and Eastern Arabic digits](https://en.wikipedia.org/wiki/Eastern_Arabic_numerals#Numerals) to Western Arabic digits
 */
fun String.normalizeDigits() = this
        // Replace Persian/Urdu numerals
        .replace(Regex("[?-?]")) { match -> (match.value.single() - '?').toString() }
        // Replace Eastern Arabic numerals
        .replace(Regex("[?-?]")) { match -> (match.value.single() - '?').toString() }

/**
 * Converts [Persian/Urdu/Eastern Arabic decimal separator](https://en.wikipedia.org/wiki/Decimal_separator#Other_numeral_systems) `?` or slash `/` (invalid and non-standard) to `.` (decimal separator in English)
 */
fun String.normalizeDecimalSeparator() = this.replace('?', '.').replace('/', '.')

/**
 * Removes everything except Western Arabic digits and point `.` (for example, thousands separators)
 */
fun String.removeOptionalCharacters() = this.replace(Regex("[^\\d.]"), "")

See this Wikipedia article for difference between numerals.

Solution 7:[7]

Only 6 lines in Kotlin

val ar = "-????????"

val en = ar.map {
    if (it.code in 1632..1641) (it.code - 1632 + 48).toChar()
    else it
}.joinToString("")

Here, 1632 & 1641 are the values of 0(zero) & 9(nine) respectively in Arabic.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Flovettee
Solution 2 Mahmoud Mabrok
Solution 3 Parisa Baastani
Solution 4 Younes Belouche
Solution 5 Suraj Rao
Solution 6
Solution 7 philoopher97