Arabic engineering reference
Arabic Digits: Unicode and JavaScript Reference
Arabic-Indic digits and Extended Arabic-Indic digits encode the same decimal values as Western digits using different Unicode characters. This reference maps all thirty characters, provides copyable JavaScript conversion examples, and separates numeric storage from localized display so validation, parsing, and sorting can follow an explicit input policy.
Thirty digits, three encodings
The value column is the decimal value, not the encoded character. Arabic-Indic digits occupy U+0660–U+0669; Extended Arabic-Indic digits occupy U+06F0–U+06F9. HTML entities and JavaScript escapes below represent individual characters, not entire formatted numbers.
| Value | Set | Glyph | Code point | HTML entity | JS escape |
|---|---|---|---|---|---|
| 0 | Western / ASCII | 0 | U+0030 | 0 | \u0030 |
| 1 | Western / ASCII | 1 | U+0031 | 1 | \u0031 |
| 2 | Western / ASCII | 2 | U+0032 | 2 | \u0032 |
| 3 | Western / ASCII | 3 | U+0033 | 3 | \u0033 |
| 4 | Western / ASCII | 4 | U+0034 | 4 | \u0034 |
| 5 | Western / ASCII | 5 | U+0035 | 5 | \u0035 |
| 6 | Western / ASCII | 6 | U+0036 | 6 | \u0036 |
| 7 | Western / ASCII | 7 | U+0037 | 7 | \u0037 |
| 8 | Western / ASCII | 8 | U+0038 | 8 | \u0038 |
| 9 | Western / ASCII | 9 | U+0039 | 9 | \u0039 |
| 0 | Arabic-Indic | ٠ | U+0660 | ٠ | \u0660 |
| 1 | Arabic-Indic | ١ | U+0661 | ١ | \u0661 |
| 2 | Arabic-Indic | ٢ | U+0662 | ٢ | \u0662 |
| 3 | Arabic-Indic | ٣ | U+0663 | ٣ | \u0663 |
| 4 | Arabic-Indic | ٤ | U+0664 | ٤ | \u0664 |
| 5 | Arabic-Indic | ٥ | U+0665 | ٥ | \u0665 |
| 6 | Arabic-Indic | ٦ | U+0666 | ٦ | \u0666 |
| 7 | Arabic-Indic | ٧ | U+0667 | ٧ | \u0667 |
| 8 | Arabic-Indic | ٨ | U+0668 | ٨ | \u0668 |
| 9 | Arabic-Indic | ٩ | U+0669 | ٩ | \u0669 |
| 0 | Extended Arabic-Indic | ۰ | U+06F0 | ۰ | \u06F0 |
| 1 | Extended Arabic-Indic | ۱ | U+06F1 | ۱ | \u06F1 |
| 2 | Extended Arabic-Indic | ۲ | U+06F2 | ۲ | \u06F2 |
| 3 | Extended Arabic-Indic | ۳ | U+06F3 | ۳ | \u06F3 |
| 4 | Extended Arabic-Indic | ۴ | U+06F4 | ۴ | \u06F4 |
| 5 | Extended Arabic-Indic | ۵ | U+06F5 | ۵ | \u06F5 |
| 6 | Extended Arabic-Indic | ۶ | U+06F6 | ۶ | \u06F6 |
| 7 | Extended Arabic-Indic | ۷ | U+06F7 | ۷ | \u06F7 |
| 8 | Extended Arabic-Indic | ۸ | U+06F8 | ۸ | \u06F8 |
| 9 | Extended Arabic-Indic | ۹ | U+06F9 | ۹ | \u06F9 |
Choose a numbering system explicitly
Arabic-Indic digits occur in Arabic-language contexts; Extended Arabic-Indic digits are used in Persian and Urdu contexts. European digits are also used in many Arabic-speaking North African countries. Regional preferences vary. A language tag alone is not a promise of a particular digit set: inspect resolvedOptions().numberingSystem and specify numberingSystem when your product requires a stable choice.
Intl.NumberFormat formats numeric values; it does not parse localized input. These examples deliberately request arab, arabext and latn rather than relying on the runtime’s locale defaults.
for (const locale of ["ar-EG", "ar-SA", "ar-MA", "fa-IR", "ur-PK"]) {
console.log(locale, new Intl.NumberFormat(locale).resolvedOptions().numberingSystem);
}
const value = 2026;
for (const numberingSystem of ["arab", "arabext", "latn"]) {
const formatter = new Intl.NumberFormat("ar-EG", {
numberingSystem, useGrouping: false,
});
console.log(formatter.format(value));
}Normalize digits before validating an integer
This converter maps only the two digit ranges. It intentionally leaves signs, spaces, decimal separators and grouping separators untouched. The anchored ASCII check then rejects everything outside a nonnegative integer policy. Keep identifiers as strings when leading zeros matter.
function asciiDigits(input) {
return input.replace(/[\u0660-\u0669\u06F0-\u06F9]/g, char =>
String(char.codePointAt(0) - (char <= "\u0669" ? 0x0660 : 0x06F0))
);
}
const normalized = asciiDigits("\u0661\u0662");
if (!/^[0-9]+$/.test(normalized)) throw new Error("Expected integer digits");
const value = Number(normalized);
if (!Number.isSafeInteger(value)) throw new Error("Outside safe integer range");Parsing and sorting traps
parseInt does not provide localized number parsing. A leading Arabic-Indic digit is not a base-10 ASCII digit, so parseInt returns NaN; it can also accept an ASCII prefix while ignoring a trailing invalid character. Normalize and validate the entire input first.
JavaScript \d matches ASCII digits. Use explicit ranges for the three sets accepted here; Unicode Decimal_Number also includes other scripts. Default string sorting compares encoded strings rather than numeric values. After validated numeric conversion, use a numeric comparator. For long integers, consider BigInt instead of losing precision with Number.
parseInt("\u0661\u0662", 10); // NaN
parseInt("12x", 10); // 12: not complete validation
[10, 2].sort((a, b) => a - b); // [2, 10]Related references and tools
- Arabic Tashkeel: Diacritics and Removal Regex
- Arabic Unicode Ranges: Blocks, Regex and Font Subsets
- Arabic Letter Forms: 28 Letters and Joining Rules
- Arabic Language Codes: lang, dir and hreflang
- Arabic Numeral Converter
- Arabic Text Normalizer
- Arabic Regex Patterns
- Arabic Search Normalization
- What lang="ar" and dir="rtl" each do
Questions and answers
Does Intl.NumberFormat parse Arabic digits?
No. Intl.NumberFormat formats numeric values for display. Normalize supported input digit ranges separately, validate the entire input, and then convert according to your numeric policy.
Should identifiers become JavaScript numbers?
Keep identifiers as strings when leading zeros matter. For arithmetic, validate first and check Number.isSafeInteger; use an appropriate alternative for larger integers.