Android convert Arabic number to English Number
Asked Answered
P

9

10

I get the following error from the GPS:

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

Now, this is from an 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?

Pumping answered 8/9, 2016 at 8:10 Comment(3)
For difference between numerals see this Wikipedia article.Poundfoolish
Upvote this YouTrack issue for Kotlin so you can simply call String.toDouble(): youtrack.jetbrains.com/issue/KT-58122/…Poundfoolish
These are not arabic numbers, they are Hindu numbers but used by arabs, the actual Arabic numbers are the ones widely used (0-9)Stettin
D
20

Try this:

String number = arabicToDecimal("۴۲"); // number = 42;

private static final String arabic = "\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9";
private static String arabicToDecimal(String number) {
    char[] chars = new char[number.length()];
    for(int i=0;i<number.length();i++) {
        char ch = number.charAt(i);
        if (ch >= 0x0660 && ch <= 0x0669)
           ch -= 0x0660 - '0';
        else if (ch >= 0x06f0 && ch <= 0x06F9)
           ch -= 0x06f0 - '0';
        chars[i] = ch;
    }
    return new String(chars);
}
Doldrums answered 8/9, 2016 at 8:18 Comment(1)
arabic string is never usedElodiaelodie
L
5

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
    }
Lorrimor answered 2/2, 2021 at 13:7 Comment(0)
D
3

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 '٫'

Dinge answered 21/7, 2020 at 16:52 Comment(0)
K
3

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)
Kaki answered 15/9, 2021 at 9:7 Comment(1)
You will get java.lang.IllegalArgumentException: Cannot format given Object as a Number Exception if you try to convert no English string.Dib
D
3

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.

Dib answered 15/2, 2022 at 9:29 Comment(1)
This does not work if the number contains Persian/Urdu/Arabic decimal separator (٫). In fact, your own ar variable contains that character.Poundfoolish
P
2

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');
}
Plastometer answered 16/11, 2018 at 14:8 Comment(0)
P
1

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.

Poundfoolish answered 4/11, 2021 at 14:18 Comment(0)
B
0

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(" ", "")


}
Bigler answered 30/7, 2021 at 15:8 Comment(0)
P
0

A more simple solution using Kotlin:

fun String.parseAsDouble(): Double? = this
    .map { if (it == '٫' || it == '/') '.' else it }    // See note 1
    .filter { it.isDigit() || it == '.' || it == '-' } // See note 2
    .map { it.digitToIntOrNull() ?: it }               // See note 3
    .joinToString(separator = "")
    .toDoubleOrNull()
  1. Normalizes (converts) ٫ (Persian/Urdu/Eastern Arabic decimal separator) and slash / (invalid and non-standard) to . (decimal separator in English).
    See https://en.wikipedia.org/wiki/Decimal_separator#Other_numeral_systems

  2. If you want to return null if the string contains any illegal character (like alphabet), comment or remove this line

  3. Normalizes (converts) Persian/Urdu and Eastern Arabic digits to Western Arabic digits.
    See https://en.wikipedia.org/wiki/Eastern_Arabic_numerals#Numerals

Poundfoolish answered 19/4, 2023 at 13:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.