JavaScript:如何检查字符是否为RTL?

Kry*_*nik 15 javascript unicode bidi right-to-left

如何以编程方式检查浏览器是否将某些字符视为JavaScript中的RTL?

也许创建一些透明的DIV并查看文本的放置位置?

一点背景.Unicode 5.2增加了Avestan字母表支持.因此,如果浏览器支持Unicode 5.2,它会将U + 10B00等字符视为RTL(目前只有Firefox支持).否则,它会将这些字符视为LTR,因为这是默认值.

我如何以编程方式检查这个?我正在写一个Avestan输入脚本,如果浏览器太笨,我想覆盖bidi方向.但是,如果浏览器确实支持Unicode,则不应覆盖bidi设置(因为这将允许混合Avestan和Cyrillic).

我目前这样做:

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';
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,显然,在Chrome和Opera开始支持Unicode 5.2之后,这会使脚本不太可用.

vsy*_*ync 20

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);
};
Run Code Online (Sandbox Code Playgroud)

游乐场页面


mca*_*art 6

在原始问题被问及回答之后我意识到这已经有一段时间了,但我发现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);
};
Run Code Online (Sandbox Code Playgroud)

更新

可能有一些方法可以加速上述正则表达式.使用带有惰性量词的否定字符类似乎有助于提高速度(在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);
};
Run Code Online (Sandbox Code Playgroud)


Kry*_*nik 2

感谢您的评论,但似乎我自己已经这样做了:

\n\n
function is_script_rtl(t) {\n    var d, s1, s2, bodies;\n\n    //If the browser doesn\xe2\x80\x99t support this, it probably doesn\xe2\x80\x99t support Unicode 5.2\n    if (!("getBoundingClientRect" in document.documentElement))\n        return false;\n\n    //Set up a testing DIV\n    d = document.createElement(\'div\');\n    d.style.position = \'absolute\';\n    d.style.visibility = \'hidden\';\n    d.style.width = \'auto\';\n    d.style.height = \'auto\';\n    d.style.fontSize = \'10px\';\n    d.style.fontFamily = "\'Ahuramzda\'";\n    d.appendChild(document.createTextNode(t));\n\n    s1 = document.createElement("span");\n    s1.appendChild(document.createTextNode(t));\n    d.appendChild(s1);\n\n    s2 = document.createElement("span");\n    s2.appendChild(document.createTextNode(t));\n    d.appendChild(s2);\n\n    d.appendChild(document.createTextNode(t));\n\n    bodies = document.getElementsByTagName(\'body\');\n    if (bodies) {\n        var body, r1, r2;\n\n        body = bodies[0];\n        body.appendChild(d);\n        var r1 = s1.getBoundingClientRect();\n        var r2 = s2.getBoundingClientRect();\n        body.removeChild(d);\n\n        return r1.left > r2.left;\n    }\n\n    return false;   \n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

使用示例:

\n\n
Avestan in <script>document.write(is_script_rtl(\'\') ? "RTL" : "LTR")</script>,\nArabic is <script>document.write(is_script_rtl(\'\xd8\xa7\xd9\x84\xd8\xb9\xd8\xb1\xd8\xa8\xd9\x8a\xd8\xa9\') ? "RTL" : "LTR")</script>,\nEnglish is <script>document.write(is_script_rtl(\'English\') ? "RTL" : "LTR")</script>.\n
Run Code Online (Sandbox Code Playgroud)\n\n

似乎有效。:)

\n