32

I need to convert Arabic/Persian Numbers to its English equal (for example convert "۲" to "2")

How can I do this?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Ariyan
  • 14,760
  • 31
  • 112
  • 175

14 Answers14

38

I suggest you have a ten digit lookup String and replace all the digits one at a time.

public static void main(String... args) {
    System.out.println(arabicToDecimal("۴۲"));
}
//used in Persian apps
private static final String extendedArabic = "\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9";

//used in Arabic apps
private static final String arabic = "\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669";

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);
}

prints

42

The reason for using the strings as a lookup is that other characters such as . - , would be left as is. In fact a decimal number would be unchanged.

VSB
  • 9,825
  • 16
  • 72
  • 145
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • This will change numbers in `extended Arabic-indic` Unicode sub-range (`۰` up to `۹`) to English which is usually used for representation of numbers in Persian applications. It will also changes `Arabic-indic` Unicode sub-range, which digits are ranging from 0x0660 for zero(`٠`) up to 0x0669 for nine (`۹`). Note that the digits look the same but they have different Unicode. – VSB Sep 21 '20 at 15:53
27

I achived this by java.math.BigDecimal Class, Below is the code snippet

String arabicNumerals = "۴۲۴۲.۴۲";
String englishNumerals = new BigDecimal(arabic).toString();
System.out.println("Number In Arabic : "+arabicNumerals);
System.out.println("Number In English : "+englishNumerals);

Result

Number In Arabic : ۴۲۴۲.۴۲
Number In English : 4242.42

NB: The above code will not work if there are any characteors other than numeric digits in arabicNumerals, for example: ۴,۲۴۲.۴۲ will result in a java.lang.NumberFormatException, so you may remove other characters using Character.isDigit(char ch) in another logic and use the above code. All normal cases are working.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Navas Basheer
  • 940
  • 2
  • 9
  • 17
  • 3
    This is better and more simplistic (imo) than the chosen answer. I didn't even know `BigDecimal` catered for non-Western digits. – mohammedkhan Feb 07 '16 at 22:56
14

I found a simpler and faster way which includes the two arabic code pages too.

public static String convertToEnglishDigits(String value)
{
     String newValue = value.replace("١", "1").replace("٢", "2").replace("٣", "3").replace("٤", "4").replace("٥", "5")
             .replace("٦", "6").replace("7", "٧").replace("٨", "8").replace("٩", "9").replace("٠", "0")
             .replace("۱", "1").replace("۲", "2").replace("۳", "3").replace("۴", "4").replace("۵", "5")
             .replace("۶", "6").replace("۷", "7").replace("۸", "8").replace("۹", "9").replace("۰", "0");

     return newValue;
}

It will return the numbers in English format or vise versa if you change the replace from.
("۰", "0") to ("0","۰")

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Kishath
  • 5,560
  • 4
  • 17
  • 22
  • ....doesn't that create 20 Strings each time you call it for a number? Although I guess if you don't use it in a massive for-loop, you won't have a problem from that. – EpicPandaForce Feb 03 '16 at 11:30
  • You don't call the method for each number. You simply parse the list of numbers as a string "12432475737485" and it replace the arabic characters. You could parse "gello374828SomeText" as well and get only the numbers converted to arabic – Kishath Mar 17 '16 at 07:19
  • this will work fine for a string that have arabic numbers in it i replace "replace" with "replaceAll" and you have to change replace("7", "٧") to replace( "٧", "7") – elouanesbg Dec 26 '22 at 13:35
9

Try this guys:

/**
 * Utility class to detect arabic languages and convert numbers into arabic digits.
 *
 * @author Ahmed Shakil
 * @date 09-24-2012
 */
public final class ArabicUtil {

private static final char[] DIGITS = {'\u0660','\u0661','\u0662','\u0663','\u0664','\u0665','\u0666','\u0667','\u0668','\u0669'};

/**
 * Returns <code>true</code> if the provided language code uses arabic characters; othersise <code>false</code>.
 * @param lang ISO language code.
 * @return <code>true</code> if the provided language code uses arabic characters; othersise <code>false</code>
 */
public static boolean isArabic (String lang) {
    return "ar".equals(lang) || "fa".equals(lang) || "ur".equals(lang);
}

/**
 * Convert digits in the specified string to arabic digits.
 */
public static String convertDigits (String str) {
    if (str == null || str.length() == 0) return str;

    char[] s = new char[str.length()];
    for(int i =0;i<s.length;i++)
        s[i] = toDigit( str.charAt( i ) );

    return new String(s);
}

/**
 * Convert single digit in the specified string to arabic digit.
 */
public static char toDigit (char ch) {
    int n = Character.getNumericValue( (int)ch );
    return n >=0 && n < 10 ? ARABIC[n] : ch;
}

/**
 * Convert an int into arabic string.
 */
public static String toString (int num) {
    return convertDigits( Integer.toString( num ) );
}
}

BTW there is a difference between arabic digits vs. urdu/farsi: Arabic:

private static final char[] ARABIC     = {'\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668', '\u0669'};

Urdu or Farsi:

private static final char[] URDU_FARSI = {'\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8', '\u06f9'};
Sileria
  • 15,223
  • 4
  • 49
  • 28
  • 1
    `private static final char[] ENGLISH = {'\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037', '\u0038', '\u0039'};` – Nizzy Sep 12 '13 at 06:24
5

so trivial answer:

public static String convertNumbersToPersian(String str)
{
    String answer = str;
    answer = answer.replace("1","١");
    answer = answer.replace("2","٢");
    answer = answer.replace("3","٣");
    answer = answer.replace("4","٤");
    answer = answer.replace("5","٥");
    answer = answer.replace("6","٦");
    answer = answer.replace("7","٧");
    answer = answer.replace("8","٨");
    answer = answer.replace("9","٩");
    answer = answer.replace("0","٠");
    return answer;
}

and

public static String convertNumbersToEnglish(String str) {
    String answer = str;
    answer = answer.replace("١", "1");
    answer = answer.replace("٢", "2");
    answer = answer.replace("٣", "3");
    answer = answer.replace("٤", "4");
    answer = answer.replace("٥", "5");
    answer = answer.replace("٦", "6");
    answer = answer.replace("٧", "7");
    answer = answer.replace("٨", "8");
    answer = answer.replace("٩", "9");
    answer = answer.replace("٠", "0");
    return answer;
}
Mehdi Khademloo
  • 2,754
  • 2
  • 20
  • 40
5

First make it work, then make it look nice ;-)

public static char persianDigitToEnglish(char persianDigit) {
    return (char) (((int)persianDigit) - ((int)'۲' - (int)'2'));
}

Works for 2, unfortunately I don't know other Persian digits, could You give it a try?

assertThat(persianDigitToEnglish('۲')).isEqualTo('2');

EDIT: (based on Peter Lawrey String version, but uses StringBuilder)

public static String persianDigitToEnglish(String persianNumber) {
    StringBuilder chars = new StringBuilder(persianNumber.length());
    for (int i = 0; i < persianNumber.length(); i++)
        chars.append(persianDigitToEnglish(persianNumber.charAt(i)));
    return chars.toString();
}

private static char persianDigitToEnglish(char persianDigit) {
    return (char) (((int)persianDigit) - ((int)'۲' - (int)'2'));
}
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
4

Character.getNumericValue(ch) saved my life, generic solution for any locale.

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 (Character.isDigit(ch) && !(ch >= '0' && ch <= '9')) {
            int numericValue = Character.getNumericValue(ch);
            if (numericValue >= 0) {
                builder.append(numericValue);
            }
        } else {
            builder.append(ch);
        }
    }
    return builder.toString();
}
Flovettee
  • 895
  • 1
  • 8
  • 9
3

This code will work with decimal points also:

public class mainsupport {
public static void main(String args[]){
//  String Numtoconvert="15.3201" ;
//  String Numtoconvert="458" ;
    String Numtoconvert="٨٧٫٥٩٨" ; // integer value 87.598
    
      System.out.println(getUSNumber(Numtoconvert));
}
private static String getUSNumber(String Numtoconvert){
    
    NumberFormat formatter = NumberFormat.getInstance(Locale.US);
      try {
          if(Numtoconvert.contains("٫"))      
          Numtoconvert=formatter.parse(Numtoconvert.split("٫")[0].trim())+"."+formatter.parse(Numtoconvert.split("٫")[1].trim());
          else
              Numtoconvert=formatter.parse(Numtoconvert).toString();
      } catch (ParseException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
      }
      return Numtoconvert;
}

This prints 87.598.

TylerH
  • 20,799
  • 66
  • 75
  • 101
sujith s
  • 864
  • 11
  • 20
3

i think the best way is to change the Locale to what you want for example,
for double number :

NumberFormat fmt = NumberFormat.getNumberInstance(Locale.US);
d = Double.parseDouble(s);

for String :

NumberFormat.getNumberInstance(Locale.US).format(s);

or DecimalFormat:

double num;
DecimalFormat df = new DecimalFormat("###.###");
df.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
String s = df.format(num);
Sepehr Nozaryian
  • 370
  • 4
  • 15
3

While I was looking for the most performant solution I mixed Kishath and Sileria answers and came up with a clean and fast result:

public class StringLocalizer {
    private static final char[] ENGLISH_NUMBERS = {'\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037', '\u0038', '\u0039'};
    private static final char[] PERSIAN_NUMBERS = {'\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8', '\u06f9'};
    private static final char[] ARABIC_NUMBERS = {'\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668', '\u0669'};

    public static String on(String input) {
        String lang = Locale.getDefault().getLanguage();
        boolean isPersian = "fa".equals(lang) || "ur".equals(lang);
        boolean isArabic = "ar".equals(lang);
        if (isPersian) return input
                .replace(ENGLISH_NUMBERS[0], PERSIAN_NUMBERS[0])
                .replace(ENGLISH_NUMBERS[1], PERSIAN_NUMBERS[1])
                .replace(ENGLISH_NUMBERS[2], PERSIAN_NUMBERS[2])
                .replace(ENGLISH_NUMBERS[3], PERSIAN_NUMBERS[3])
                .replace(ENGLISH_NUMBERS[4], PERSIAN_NUMBERS[4])
                .replace(ENGLISH_NUMBERS[5], PERSIAN_NUMBERS[5])
                .replace(ENGLISH_NUMBERS[6], PERSIAN_NUMBERS[6])
                .replace(ENGLISH_NUMBERS[7], PERSIAN_NUMBERS[7])
                .replace(ENGLISH_NUMBERS[8], PERSIAN_NUMBERS[8])
                .replace(ENGLISH_NUMBERS[9], PERSIAN_NUMBERS[9]);
        else if (isArabic) return input
                .replace(ENGLISH_NUMBERS[0], ARABIC_NUMBERS[0])
                .replace(ENGLISH_NUMBERS[1], ARABIC_NUMBERS[1])
                .replace(ENGLISH_NUMBERS[2], ARABIC_NUMBERS[2])
                .replace(ENGLISH_NUMBERS[3], ARABIC_NUMBERS[3])
                .replace(ENGLISH_NUMBERS[4], ARABIC_NUMBERS[4])
                .replace(ENGLISH_NUMBERS[5], ARABIC_NUMBERS[5])
                .replace(ENGLISH_NUMBERS[6], ARABIC_NUMBERS[6])
                .replace(ENGLISH_NUMBERS[7], ARABIC_NUMBERS[7])
                .replace(ENGLISH_NUMBERS[8], ARABIC_NUMBERS[8])
                .replace(ENGLISH_NUMBERS[9], ARABIC_NUMBERS[9]);
        else return input
                .replace(PERSIAN_NUMBERS[0], ENGLISH_NUMBERS[0])
                .replace(PERSIAN_NUMBERS[1], ENGLISH_NUMBERS[1])
                .replace(PERSIAN_NUMBERS[2], ENGLISH_NUMBERS[2])
                .replace(PERSIAN_NUMBERS[3], ENGLISH_NUMBERS[3])
                .replace(PERSIAN_NUMBERS[4], ENGLISH_NUMBERS[4])
                .replace(PERSIAN_NUMBERS[5], ENGLISH_NUMBERS[5])
                .replace(PERSIAN_NUMBERS[6], ENGLISH_NUMBERS[6])
                .replace(PERSIAN_NUMBERS[7], ENGLISH_NUMBERS[7])
                .replace(PERSIAN_NUMBERS[8], ENGLISH_NUMBERS[8])
                .replace(PERSIAN_NUMBERS[9], ENGLISH_NUMBERS[9])
                .replace(ARABIC_NUMBERS[0], ENGLISH_NUMBERS[0])
                .replace(ARABIC_NUMBERS[1], ENGLISH_NUMBERS[1])
                .replace(ARABIC_NUMBERS[2], ENGLISH_NUMBERS[2])
                .replace(ARABIC_NUMBERS[3], ENGLISH_NUMBERS[3])
                .replace(ARABIC_NUMBERS[4], ENGLISH_NUMBERS[4])
                .replace(ARABIC_NUMBERS[5], ENGLISH_NUMBERS[5])
                .replace(ARABIC_NUMBERS[6], ENGLISH_NUMBERS[6])
                .replace(ARABIC_NUMBERS[7], ENGLISH_NUMBERS[7])
                .replace(ARABIC_NUMBERS[8], ENGLISH_NUMBERS[8])
                .replace(ARABIC_NUMBERS[9], ENGLISH_NUMBERS[9]);
    }
}

Note that here we assumed localizing is done between English and Persian or Arabic, so if you also need to include another language in replacing criteria just add the missing replace clauses.

Sdghasemi
  • 5,370
  • 1
  • 34
  • 42
2

The following seems to me to be the simple and obvious solution. I don’t know why it hasn’t been posted before.

    Locale persian = Locale.forLanguageTag("fa");
    NumberFormat nf = NumberFormat.getIntegerInstance(persian);
    
    String persianIntegerString = "۲۱";
    
    int parsedInteger = nf.parse(persianIntegerString).intValue();

    System.out.println(parsedInteger);

Output is:

21

If we’ve got a string with a decimal point in it (or just one that may have that), use getInstance instead of getIntegerInstance. At the same time I am taking an Arabic string this time to demonstrate that this works too.

    Locale arabic = Locale.forLanguageTag("ar");
    NumberFormat nf = NumberFormat.getInstance(arabic);
    
    String arabicDecimalString = "٣٤٫٥٦";
    
    double parsedDouble = nf.parse(arabicDecimalString).doubleValue();

    System.out.println(parsedDouble);

34.56

In many cases the number formats can also parse numbers in other locales, but I doubt that it is always the case, so I would not want to rely on it.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
1

Use Locale class to convert numbers.

 Locale locale = new Locale("ar");
 String formattedArabic = format(locale, "%d", value));
Hend
  • 36
  • 2
  • 8
0

Try this for converting Persian/Arabic numbers to English:

public static String convertToEnglish(String arabicNumber) {
    for (int i = 0; i <= 9; i++) {
        arabicNumber= arabicNumber.replace((char) (1776 + i),
                (char) (48 + i));
    }
    return arabicNumber;
}
-3

I think instead of replacing the digits one by one (which would only work for decimal numbers), you should parse your number with a persian NumberFormat to a number, and then (if necessary) use a english NumberFormat to format it again.

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210