Skip to content

Instantly share code, notes, and snippets.

@MoshDev
Created September 22, 2014 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save MoshDev/decb9f4755d410c9db44 to your computer and use it in GitHub Desktop.
Save MoshDev/decb9f4755d410c9db44 to your computer and use it in GitHub Desktop.
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