Created
September 22, 2014 13:06
-
-
Save MoshDev/decb9f4755d410c9db44 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.mosh.arabicfix; | |
/** | |
(Mosh Arabic Shaper) this API should fix Arabic shapes used within Android views, and canvas. | |
Copyright (C) 2011 Mohammad Mshari Ersan (mosh_java@yahoo.com) | |
* IF YOU LIKED IT, DONATE BY HIRING ME, OR LET ME MAKE YOUR PROJECT. | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
/** | |
* | |
* @author Mohammad Ersan | |
*/ | |
public final class ArabicMosh { | |
private static int[][] letters = new int[][] { { 65152, 65152, 65152, 65152, 1569, 0 }, | |
{ 65153, 65154, 65153, 65154, 1570, 1 }, { 65155, 65156, 65155, 65156, 1571, 1 }, | |
{ 65157, 65158, 65157, 65158, 1572, 1 }, { 65159, 65160, 65159, 65160, 1573, 1 }, | |
{ 65161, 65162, 65163, 65164, 1574, 3 }, { 65165, 65166, 65165, 65166, 1575, 1 }, | |
{ 65167, 65168, 65169, 65170, 1576, 3 }, { 65171, 65172, 65171, 65172, 1577, 1 }, | |
{ 65173, 65174, 65175, 65176, 1578, 3 }, { 65177, 65178, 65179, 65180, 1579, 3 }, | |
{ 65181, 65182, 65183, 65184, 1580, 3 }, { 65185, 65186, 65187, 65188, 1581, 3 }, | |
{ 65189, 65190, 65191, 65192, 1582, 3 }, { 65193, 65194, 65193, 65194, 1583, 1 }, | |
{ 65195, 65196, 65195, 65196, 1584, 1 }, { 65197, 65198, 65197, 65198, 1585, 1 }, | |
{ 65199, 65200, 65199, 65200, 1586, 1 }, { 65201, 65202, 65203, 65204, 1587, 3 }, | |
{ 65205, 65206, 65207, 65208, 1588, 3 }, { 65209, 65210, 65211, 65212, 1589, 3 }, | |
{ 65213, 65214, 65215, 65216, 1590, 3 }, { 65217, 65218, 65219, 65220, 1591, 3 }, | |
{ 65221, 65222, 65223, 65224, 1592, 3 }, { 65225, 65226, 65227, 65228, 1593, 3 }, | |
{ 65229, 65230, 65231, 65232, 1594, 3 }, { 1600, 1600, 1600, 1600, 1600, 3 }, | |
{ 65233, 65234, 65235, 65236, 1601, 3 }, { 65237, 65238, 65239, 65240, 1602, 3 }, | |
{ 65241, 65242, 65243, 65244, 1603, 3 }, { 65245, 65246, 65247, 65248, 1604, 3 }, | |
{ 65249, 65250, 65251, 65252, 1605, 3 }, { 65253, 65254, 65255, 65256, 1606, 3 }, | |
{ 65257, 65258, 65259, 65260, 1607, 3 }, { 65261, 65262, 65261, 65262, 1608, 1 }, | |
{ 65263, 65264, 65263, 65264, 1609, 1 }, { 65265, 65266, 65267, 65268, 1610, 3 } }; | |
private static int[][] harakat = new int[][] { { 65136, 65136, 65136, 65137, 1611, 3 }, | |
{ 65138, 65138, 65138, 65138, 1612, 3 }, { 65140, 65140, 65140, 65140, 1613, 3 }, | |
{ 65142, 65142, 65142, 65143, 1614, 3 }, { 65144, 65144, 65144, 65145, 1615, 3 }, | |
{ 65146, 65146, 65146, 65147, 1616, 3 }, { 65148, 65148, 65148, 65149, 1617, 3 }, | |
{ 65150, 65150, 65150, 65151, 1618, 3 } }; | |
private static int POSITION_ALONE = 0; | |
private static int POSITION_END = 1; | |
private static int POSITION_START = 2; | |
private static int POSITION_MIDDLE = 3; | |
private static final int COUNT = 1569; | |
private static final int DIFF = 5; | |
private static boolean needReverse = false; | |
public static String getFix(String strText, boolean reverse) { | |
if (strText.indexOf('\n') > 0) { | |
StringBuffer stringBuffer = new StringBuffer(strText.length()); | |
String[] strb = strText.split("\n"); | |
for (String s : strb) { | |
stringBuffer.append(fixString(s, reverse)); | |
stringBuffer.append('\n'); | |
} | |
return stringBuffer.toString(); | |
} else { | |
return fixString(strText, reverse); | |
} | |
} | |
private static String fixString(String strText, boolean reverse) { | |
needReverse = reverse; | |
char[] txtChars = strText.toCharArray(); | |
StringBuffer stringBuffer = new StringBuffer(txtChars.length); | |
char[] result; | |
char currentChar; | |
for (int s = 0; s < txtChars.length; s++) { | |
currentChar = txtChars[s]; | |
if ((currentChar >= 1569 && currentChar <= 1610) || (currentChar >= 1611 && currentChar <= 1618)) { | |
s += getArabic(stringBuffer, txtChars, s); | |
} else { | |
s += getOther(stringBuffer, txtChars, s); | |
} | |
} | |
result = stringBuffer.toString().toCharArray(); | |
if (needReverse) { | |
reverse(result); | |
} | |
return new String(result); | |
} | |
private static int arabicCounter = 0; | |
private static int getArabic(StringBuffer org, char[] cs, int pos) { | |
StringBuffer buffer = new StringBuffer(); | |
arabicCounter = 0; | |
while ((pos + arabicCounter < cs.length) | |
&& ((cs[pos + arabicCounter] >= 1569 && cs[pos + arabicCounter] <= 1610) || (cs[pos + arabicCounter] >= 1611 && cs[pos | |
+ arabicCounter] <= 1618))) { | |
if (cs[pos + arabicCounter] >= 1611 && cs[pos + arabicCounter] <= 1618) { | |
char c = getHarkeh(cs[pos + arabicCounter]); | |
buffer.append(c); | |
arabicCounter++; | |
continue; | |
} | |
buffer.append(getChar(((pos + arabicCounter) == 0 ? (char) 0 : cs[pos + arabicCounter - 1]), cs[pos | |
+ arabicCounter], | |
((pos + arabicCounter + 1) >= cs.length ? (char) 0 : cs[pos + arabicCounter + 1]), cs, pos | |
+ arabicCounter)); | |
arabicCounter++; | |
if ((pos + arabicCounter < cs.length) && (cs[pos + arabicCounter] < 1569 || cs[pos + arabicCounter] > 1610)) { | |
if ((pos + arabicCounter + 1 < cs.length) | |
&& (cs[pos + arabicCounter + 1] < 1569 || cs[pos + arabicCounter + 1] > 1610)) { | |
arabicCounter += getOther(org, cs, pos + arabicCounter); | |
} else { | |
buffer.append(cs[pos + arabicCounter]); | |
arabicCounter++; | |
} | |
} | |
} | |
buffer = reverse(buffer); | |
org.append(buffer); | |
if (arabicCounter > 0) { | |
arabicCounter -= 1; | |
} | |
return arabicCounter; | |
} | |
private static int getOther(StringBuffer org, char[] cs, int pos) { | |
StringBuffer numberBuffer = new StringBuffer(); | |
int count = 0; | |
while ((pos + count < cs.length) && (cs[pos + count] < 1569 || cs[pos + count] > 1610)) { | |
numberBuffer.append(cs[pos + count]); | |
count++; | |
} | |
if (needReverse) { | |
numberBuffer = reverse(numberBuffer); | |
} | |
org.append(numberBuffer); | |
if (count > 0) { | |
count -= 1; | |
} | |
return count; | |
} | |
private static char getHarkeh(char org) { | |
return (char) harakat[(int) org - 1611][POSITION_ALONE]; | |
} | |
private static void reverse(char[] array) { | |
if (array == null) { | |
return; | |
} | |
int i = 0; | |
int j = array.length - 1; | |
char tmp; | |
while (j > i) { | |
tmp = array[j]; | |
array[j] = array[i]; | |
array[i] = tmp; | |
j--; | |
i++; | |
} | |
} | |
private static StringBuffer reverse(StringBuffer buffer) { | |
if (buffer == null) { | |
return buffer; | |
} | |
char[] array = buffer.toString().toCharArray(); | |
reverse(array); | |
return new StringBuffer(new String(array)); | |
} | |
private static char getChar(char before, char c, char after, char[] chars, int currentPos) { | |
if (c < 1569 || c > 1610) { | |
return c; | |
} | |
boolean isBeforeIsHarkeh = false; | |
if (before >= 1611 && before <= 1618) { | |
isBeforeIsHarkeh = true; | |
} | |
boolean isAfterIsHarkeh = false; | |
if (after >= 1611 && after <= 1618) { | |
isAfterIsHarkeh = true; | |
} | |
if (c == 1604 && (after == 1570 || after == 1571 || after == 1573 || after == 1575)) { | |
arabicCounter++; | |
int beforePos = POSITION_END; | |
if (before >= 1569 && before <= 1618) { | |
beforePos = (!isBeforeIsHarkeh ? letters[(before - COUNT)][5] : harakat[(before - 1611)][5]); | |
} | |
if (after == 1570) { | |
if (beforePos == POSITION_ALONE || beforePos == POSITION_END) { | |
return (char) 65269; | |
} else { | |
return (char) 65270; | |
} | |
} | |
if (after == 1571) { | |
if (beforePos == POSITION_ALONE || beforePos == POSITION_END) { | |
return (char) 65271; | |
} else { | |
return (char) 65272; | |
} | |
} | |
if (after == 1573) {// إ | |
if (beforePos == POSITION_ALONE || beforePos == POSITION_END) { | |
return (char) 65273; | |
} else { | |
return (char) 65274; | |
} | |
} | |
if (after == 1575) { | |
if (beforePos == POSITION_ALONE || beforePos == POSITION_END) { | |
return (char) 65275; | |
} else { | |
return (char) 65276; | |
} | |
} | |
} | |
if (c > 1599) { | |
c -= DIFF; | |
} | |
if (after > 1599 && after <= 1610) { | |
after -= DIFF; | |
} | |
if (before > 1599 && before <= 1610) { | |
before -= DIFF; | |
} | |
int position = POSITION_ALONE; | |
if (before < 1569 || before > 1618) { | |
position = POSITION_START; | |
} | |
if ((before < 1569 || before > 1618) && (after < 1569 || after > 1618)) { | |
position = POSITION_ALONE; | |
} | |
if (before >= 1569 && before <= 1618 && after >= 1569 && after <= 1618) { | |
position = POSITION_MIDDLE; | |
int beforePos = (!isBeforeIsHarkeh ? letters[(before - COUNT)][5] : harakat[(before - 1611)][5]); | |
if (beforePos == POSITION_END) { | |
position = POSITION_START; | |
if (isAfterIsHarkeh) { | |
if ((currentPos + 2) >= chars.length || (chars[(currentPos + 2)] < 1569) | |
|| (chars[(currentPos + 2)] > 1618)) { | |
position = POSITION_ALONE;// needs to add support for 2 | |
// harakeh in same time | |
} | |
} | |
} | |
} | |
if (before >= 1569 && before <= 1618 && (after < 1569 || after > 1618)) { | |
position = POSITION_END; | |
int beforePos = (!isBeforeIsHarkeh ? letters[(before - COUNT)][5] : harakat[(before - 1611)][5]); | |
if (beforePos == POSITION_END) { | |
position = POSITION_ALONE; | |
} | |
} | |
return (char) letters[c - COUNT][position]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment