PDA

Просмотр полной версии : Парсер для иврита


wvxvw
09.11.2006, 04:18
В принципе можно тему и в "Для начинающих" было запостить. Вобщем, модератору виднее. =)

Значит, решил я сделать парсер для иврита. Сначала объясню, зачем он вообще нужен.
Дело в том, что если пытатьтся отрендерить ивритский текст с использованием шрифтов из библиотеки в програмно созданном текстовом поле, то возникает довольно неприятная ситуация: плеер "не понимает" в какую сторону нужно читать текст и отображает ивритские тексты задом на перед, но это еще пол беды... А вот когда нужно сделать так, чтобы в текстовом поле отображались одновременно иврит и английский - начинаются более серьезные неприятности. К сожалению, для ивритских шрифтов не предусмотрены "родные" знаки препинания, поэтому, как правило, никто не делает флешек с использованием не системных шрифтов, ну или просто пользуются посторонним софтом для того, чтобы конвертнуть текст "зеркально" и потом уже такой вставлять во флешку. К сожалению, второй вариант так же имеет недостатки. Т.как если у заказчика нет (как правило ее таки нет) програмы для переворачивания текста, то он не сможет самовольно ничего поменять на сайте.

Код ниже - практически работающее решение проблемы, увы, у него есть 2 серьезных недостатка.
1. Мне не удалось решить проблему с wordWrap, т.е. если этот параметр у поля выставлен в true, то строки начинают отображаться в обратном порядке.
2. На мой взгляд, код через чур громоздкий. И я бы был очень признателен за любые советы по оптимизации.
class HebrewConvertor {
static function conv(_str:String):String {
var tt_arr:Array = _str.split("\r\n");
for (var ii = 0; ii<tt_arr.length; ii++) {
var t_arr:Array = tt_arr[ii].split("");
var h_arr:Array = [];
var h_str:String = "";
var j:Number = 0;
for (var i = 0; i<t_arr.length; i++) {
var tmp_arr:Array = [];
if (t_arr[i].charCodeAt(0)>=1488) {
for (j=i; j<t_arr.length && t_arr[j].charCodeAt(0)>=1488; j++) {
tmp_arr.push(t_arr.splice(j, 1, "%"));
}
tmp_arr.reverse();
h_arr.push(tmp_arr.join(""));
}
}
h_arr.reverse();
for (var i = 0; i<t_arr.length; i++) {
if (t_arr[i] == "%") {
for (j=i+1; j<t_arr.length && t_arr[j] == "%"; ) {
t_arr.splice(j, 1);
}
}
}
t_arr = t_arr.join("").split("%");
for (var i = 0; i<t_arr.length; i++) {
for (j=0; j<t_arr[i].length; j++) {
if (t_arr[i].charAt(j) == "-" || t_arr[i].charAt(j) == "\"" || t_arr[i].charAt(j) == ":" || t_arr[i].charAt(j) == ";" || t_arr[i].charAt(j) == "." || t_arr[i].charAt(j) == "," || t_arr[i].charAt(j) == " ") {
var tmp_arr:Array = t_arr[i].split("");
t_arr[i] = HebrewConvertor.en_sort(tmp_arr);
break;
}
}
}
t_arr.reverse();
var rt:String = "";
for (var i = 0; i<t_arr.length; i++) {
h_arr[i] != undefined ? rt += t_arr[i]+h_arr[i] : "";
}
tt_arr[ii] = rt;
}
return tt_arr.join("\r\n");
}
static function en_sort(_arr:Array):String {
var end_arr:Array = [];
var tmp_arr:Array = [];
var tmp1_arr:Array = [];
var tmp_str:String = "";
var r_arr:Array = _arr;
if (r_arr.length>1) {
for (var i = 0; i<_arr.length; i++) {
if (r_arr[i] == " " || r_arr[i] == ":" || r_arr[i] == ";" || r_arr[i] == "-" || r_arr[i] == "," || r_arr[i] == "." || r_arr[i] == "\"") {
for (var j = i; (r_arr[j] == " " || r_arr[j] == ":" || r_arr[j] == ";" || r_arr[j] == "-" || r_arr[j] == "," || r_arr[j] == "." || r_arr[j] == "\"") && j<r_arr.length; j++) {
tmp_arr.push(r_arr.splice(j, 1, "%"));
i++;
}
tmp_arr.reverse();
tmp_str = tmp_arr.join("");
tmp1_arr.splice(0, 1, r_arr.join(""));
tmp_arr.splice(0);
}
end_arr.push(tmp_str);
end_arr.reverse();
tmp_str = "";
}
tmp1_arr = tmp1_arr.toString().split("");
for (var i = 0; i<tmp1_arr.length; i++) {
if (tmp1_arr[i] == "%" && tmp1_arr[i+1] == "%") {
tmp1_arr.splice(i+1, 1);
i--;
}
}
for (var i = 0; i<tmp1_arr.length; i++) {
if (tmp1_arr[i] == "%") {
tmp1_arr[i] = end_arr.splice(0, 1);
}
}
tmp_str = tmp1_arr.join("");
} else {
tmp_str = r_arr.join("");
}
return tmp_str;
}
}

iNils
09.11.2006, 05:15
Было бы не плохо выложить пример исходного текста иврита в перемешку с латиницей и что из этого должно получится.

7thsky™
09.11.2006, 09:29
Есть зеркальные шрифты, спроси любого кто пользуется фрихандом.

твоя проблема очень просто решается с зеркальными шрифтами.

1. Устанавливается фонт зеркальный
2. текстовое поле флипится по вертикали
3. пробегаешься по тексту находишь английские слова и меняешь порядок букв на обратный

единственное но. фонт должен быть включен в свф

С невключенными шрифтами, сложнее...

wvxvw
09.11.2006, 11:05
2 7thsky:
Да оно конечно хорошо, когда есть иксовые фонты =) а когда нет? А заказчику нужен, ну вот хоть застрелись, именно этот (он его купил, например =). Я могу переделать шрифт в фонтографере... но это кучу времени займет... (Кроме того, копирайты всякие... а если я случайно шрифт моего бывшего бывшего преподавателя "сопру"? Не красиво как-то) Если делать по-уму, то нужно делать битмапы хотябы под 2-5 разных размеров, (пиксельные метрики шрифтов) - это у меня как минимум неделя уйдет.

Да, речь идет именно об фонте включенном в СВФ.
ЗЫ. Пользуюсь фрихендом, очень активно =)

2 iNils:
Чуть попозже выложу, надо еще придумать как =)

7thsky™
09.11.2006, 17:44
Если заказчик купил этот шрифт и он на ифрите, то практически сто пудово что есть его аналог Х, так что убеди его купить.

Потом поищи на flashoo.co.il, я помню там Mattman вроде выкладывал готовое решение.

Потом решение с текстом ОБЯЗАННО быть привязанно к текстовому полю, так как тебе еще надо разбивать на строки и менять их очередность.
Я давным давно это делал как то :) если найду вечером дома то вышлю если нужно

wvxvw
09.11.2006, 20:55
_root.win = new Uwindow(_str);
var tl:TXTLoader = new TXTLoader("texts/contact.txt");
tl.onData = function(_str:String) {
var res_str:String = "";
var t_arr:Array = _str.split("\r\n");
for (var ii = 0; ii<t_arr.length; ii++) {
var tmp_arr:Array = t_arr[ii].split(" ");
for (var i = -1; i<tmp_arr.length-1; ) {
if (tmp_arr.length>3) {
res_str += tmp_arr.splice(0, 4).join(" ")+"\r\n";
} else {
res_str += tmp_arr.join(" ")+"\r\n";
tmp_arr = [];
}
}
res_str += "\r\n";
}
while (res_str.substr(-2) == "\r\n") {
res_str = res_str.substring(0, res_str.length-2);
}
_root.win.createScrollField(HebrewConvertor.conv(res_str), {XX:10, YY:60}, {W:Stage.width-20, H:100}, _root.greenTF);

Ну это для начала привязка к текстовому полю. Сорри, вырвал из контекста, вобщем:
Uwindow - мой класс создающий страницу сайта
TXTLoader - класс-загрузчик текстов
_root.win.createScrollField() метод класса Uwindow создающий текстовое поле с некоторыми нужными мне изменениями.

Вот, попробую наглядно объяснить:
15718
Это так будет отображаться текст если ничего с ним не делать, используя системные шрифты. В большинстве случаев - это просто не приемлимо, прочитать вообще не возможно. Единственный вариант, который более-менее читается - "_sans"

15717
Кроме этого есть неприятность с выделением как созданным вручную, так и програмно, выделенная область переворачивается зеркально.

15719
Так выглядит все тот же текст отрендеренный с помощью встроенных (библиотечных) шрифтов. С использованием функции-конвертора из первого поста.

15716
Так выглядел бы сконвертированный текст, если бы отображался с помощбю системных шрифтов

15720
Так выглядит текст, если его не конвертировать, но использовать при этом для рендеринга встроенный шрифт

iNils
09.11.2006, 21:09
Я говорил про текстовые файлы, то есть сделать *.txt в utf-8. Так как я ни чего не понимаю в иврите, то желательно подобрать символы весьма различные по написанию + немного латинских. Одной строчки будет достаточно.

wvxvw
09.11.2006, 21:09
2 7thSky:
Вроде искал... видно плохо искал.
А по поводу иксовых шрифтов... Ну, если честно... плохое это решение.
Из наверное сотни, которые у меня есть, половина вообще не в той раскладке, у части не хватает каких-нибудь символов, у некоторых отсутствуют напрочь латиница или спецсимволы. Наверное только у десяти из них сделаны битовые карты (при маленьком кегле просто невозможно использовать что-нибудь кроме битмаповской отрисовки). Но и у той части, у которой эти карты таки да есть, они зачастую автосгенеренные фонтографером - опять же, гадость.
Того же несчастного Наркиса-тама у меня наверное 5 вариантов, и только 1 более-менее рабочий.
А по поводу купить-заказать сделать хороший шрифт - так я только за =) Вот ток не всегда получается уламать заказчика =)... да и времени не всегда хватает.

wvxvw
09.11.2006, 21:14
15721
Вот, в таком виде оно приходит от заказчика

15722
Вот так надо отрисовать

Сорри, не подумал :rolleyes:

iNils
09.11.2006, 21:25
А можно все таки сделать пример с одной строчкой символов на 20 в перемешку с латиницей, еще символов 5, (до и после), а то я уже глаза сломал :)

7thsky™
10.11.2006, 12:29
15721
Вот, в таком виде оно приходит от заказчика

15722
Вот так надо отрисовать

Сорри, не подумал :rolleyes:

Еще раз, решение должно быть жестко привязанно к текстовому полю где текст должен быть отображен.
Самоя правильная разбивка на строчки будет если ты просто будешь добавлять по символу в текстовое поле, и смотреть когда измениться maxscroll, это медленно, но зато 100% правильность, можно еще пользовать TextFormat.getTextExtent (str, textFieldInstance._width), но у него есть погрешности.

Проблему с выделением не решить ни как.

Вот то что давно делал нашел - 15729
Я там не пользовал вордврап, (честно говоря пользоваться им это извращение (ИМХО)) и не переворачивал английские слова, но если сначала пробежать по тексту и перевернуть английский, а потом засунуть в мой метод, получиться нормальный текст.

Использование х фонтов с ивритом, это самое нормальное решение исходя из того что макромедия не удосужилась внести поддержку райт ту лефт направления.
вот делал год назад - http://www.enerco.co.il - там пользовали - x_spacer - не плохо выглядит в мелком кегле даже как ембед фонт и включенным альясингом. Вообще 8 флэш с его альясингом просто спасение, и пользование битмап шрифтами...

wvxvw
11.11.2006, 06:07
2 iNils:
Сорри, работа. Не всегда есть возможность оперативно отписаться. Вот короткие примеры:
15748
- полученный от заказчика
15747
- сконвертированый

2 7thsky:
Смотри, проблему с привязкой к полю я решил. Т.е. это больше не проблема. Пример я привел выше. Добавлять по символу в строку - ну извини, но никак не подходит =) зачем мне нужны переносы по 1 букве? %) Надо добавлять по словам. Метод, конечно, не идеальный, но все-тки не так криво =)
Т.е. принцип такой: в зависимости от ширины целевого текстового поля и размера шрифта (ну тут немножко нужно поэксперементировать), но в принципе можно сразу прикинуть по сколько слов делать в строке. Ну а потом проверить а не появился ли maxhscroll, если да, то растягивать поле, пока не он исчезнет - такой вот "автосайз" %) Конечно, возможны глюки с очень динными "словами", типа веб-адресов или какими-нибудь географическими названиями в Германии, но, это тоже решаемо =) (просто при наборе добавлять пару лишних пробелов).

Я не говорю, что все иксовые шрифты никуда не годятся. Есть и нормально сделанные. Вопрос в другом, иногда получить нужный иксовый шрифт - проблема, которую нельзя решить в течение недели. А это очень большой срок, если ты не фрилансер, а работаешь в каком-нибудь РА.

ЗЫ. Пример скачал, завтра уже посмотрю. =) Спасибо в любом случае.

wvxvw
11.11.2006, 06:18
2 7thsky:
Все таки не удержался, посмотрел... ну, я бы не сказал, что это решение лучше... хотя рациональное зерно в этом есть. По объему кода и количеству выполненых операций примерно то же, что и у меня получается.