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)