JavaScript: как проверить, является ли символ RTL?
Как я могу программно проверить, обрабатывает ли браузер какой-либо символ как RTL в JavaScript?
Может быть, создать прозрачный DIV и посмотреть, где находится текст?
Немного контекста. Unicode 5.2 добавила поддержку алфавита Avestan. Итак, если браузер поддерживает Unicode 5.2, он обрабатывает такие символы, как U + 10B00, как RTL (в настоящее время только Firefox). В противном случае он обрабатывает эти символы как LTR, потому что это значение по умолчанию.
Как программно проверить это? Я пишу вход Avestan script, и я хочу переопределить направление bidi, если браузер слишком тупой. Но если браузер поддерживает Unicode, настройки биди не должны быть переопределены (так как это позволит смешивать Avestan и кириллицу).
В настоящее время я делаю это:
var ua = navigator.userAgent.toLowerCase();
if (ua.match('webkit') || ua.match('presto') || ua.match('trident')) {
var input = document.getElementById('orig');
if (input) {
input.style.direction = 'rtl';
input.style.unicodeBidi = 'bidi-override';
}
}
Но, очевидно, это уменьшит использование script после того, как Chrome и Opera начнут поддерживать Unicode 5.2.
Ответы
Ответ 1
Спасибо за ваши комментарии, но, похоже, я сделал это сам:
function is_script_rtl(t) {
var d, s1, s2, bodies;
//If the browser doesn’t support this, it probably doesn’t support Unicode 5.2
if (!("getBoundingClientRect" in document.documentElement))
return false;
//Set up a testing DIV
d = document.createElement('div');
d.style.position = 'absolute';
d.style.visibility = 'hidden';
d.style.width = 'auto';
d.style.height = 'auto';
d.style.fontSize = '10px';
d.style.fontFamily = "'Ahuramzda'";
d.appendChild(document.createTextNode(t));
s1 = document.createElement("span");
s1.appendChild(document.createTextNode(t));
d.appendChild(s1);
s2 = document.createElement("span");
s2.appendChild(document.createTextNode(t));
d.appendChild(s2);
d.appendChild(document.createTextNode(t));
bodies = document.getElementsByTagName('body');
if (bodies) {
var body, r1, r2;
body = bodies[0];
body.appendChild(d);
var r1 = s1.getBoundingClientRect();
var r2 = s2.getBoundingClientRect();
body.removeChild(d);
return r1.left > r2.left;
}
return false;
}
Пример использования:
Avestan in <script>document.write(is_script_rtl('𐬨𐬀𐬰𐬛𐬂') ? "RTL" : "LTR")</script>,
Arabic is <script>document.write(is_script_rtl('العربية') ? "RTL" : "LTR")</script>,
English is <script>document.write(is_script_rtl('English') ? "RTL" : "LTR")</script>.
Кажется, что сработало.:)
Ответ 2
function isRTL(s){
var ltrChars = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF'+'\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF',
rtlChars = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC',
rtlDirCheck = new RegExp('^[^'+ltrChars+']*['+rtlChars+']');
return rtlDirCheck.test(s);
};
страница детской площадки
Ответ 3
Я понимаю, что через некоторое время после того, как был задан исходный вопрос и ответили, но я нашел, что обновление vsync довольно полезно и просто захотелось добавить некоторые замечания. Я бы добавил это в комментарии к его ответу, но моя репутация еще недостаточно высока.
Вместо регулярного выражения, которое ищет от начала строки нуль или более символов, отличных от LTR, и затем одного символа RTL, не было бы больше смысла искать с начала нулевой линии или более слабой/нейтральной символы, а затем один символ RTL? В противном случае у вас есть возможность совместить много символов RTL без необходимости. Я бы приветствовал более тщательное рассмотрение моей группы слабых/нейтральных персонажей, поскольку я просто использовал отрицание комбинированных групп символов LTR и RTL.
Кроме того, не должны ли такие символы, как метки LTR/RTL, вставлять, переопределения в соответствующие группировки символов?
Я бы подумал, что окончательный код должен выглядеть примерно так:
function isRTL(s){
var weakChars = '\u0000-\u0040\u005B-\u0060\u007B-\u00BF\u00D7\u00F7\u02B9-\u02FF\u2000-\u2BFF\u2010-\u2029\u202C\u202F-\u2BFF',
rtlChars = '\u0591-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC',
rtlDirCheck = new RegExp('^['+weakChars+']*['+rtlChars+']');
return rtlDirCheck.test(s);
};
Update
Могут быть некоторые способы ускорить вышеуказанное регулярное выражение. Использование отрицательного символьного класса с ленивым квантификатором, по-видимому, помогает повысить скорость (проверено на http://regexhero.net/tester/?id=6dab761c-2517-4d20-9652-6d801623eeec, сайту требуется Silverlight 5)
Кроме того, если направленность строки неизвестна, я предполагаю, что в большинстве случаев строка будет LTR вместо RTL, и создание функции isLTR
вернет результаты быстрее, если это так, но, поскольку OP задает вопрос для isRTL
, обеспечит функцию isRTL
:
function isRTL(s){
var rtlChars = '\u0591-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC',
rtlDirCheck = new RegExp('^[^'+rtlChars+']*?['+rtlChars+']');
return rtlDirCheck.test(s);
};
Ответ 4
Сначала обратимся к вопросу в заголовке:
В JavaScript нет инструментов для доступа к свойствам символов Unicode. Вам нужно будет найти библиотеку или услугу для этой цели (я боюсь, что это может быть сложно, если вам нужно что-то надежное) или для извлечения соответствующей информации из "базы данных" Юникода (сбор текстовых файлов в определенных форматах) и для написания собственного кода для его использования.
Тогда вопрос в теле сообщения:
Это кажется еще более отчаянным. Но поскольку это, вероятно, будет чем-то ограниченным для пользователей, которые хорошо осведомлены и знают Avestan, возможно, было бы не так уж плохо отображать строку символов Avestan вместе с изображением их в правильной направленности и попросить пользователя нажать на если заказ неправильный. И вы можете сохранить этот выбор в cookie, так что пользователю нужно сделать это только один раз (для каждого браузера, хотя это должен быть относительно недолговечный файл cookie, так как браузер может обновиться).
Ответ 5
Тестирование как на иврите, так и на арабском языке (единственные современные языки/набор символов RTL, которые я знаю, которые текут справа налево, за исключением любых связанных с персидским языком, которые я не изучил):
/[\u0590-\u06FF]/.test(textarea.value)
Больше исследований предлагает что-то вроде:
/[\u0590-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]/.test(textarea.value)