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

时间:2012-08-17 12:44:48

标签: javascript unicode right-to-left bidi

如何以编程方式检查浏览器是否将某些字符视为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';
    }
}

但是,显然,在Chrome和Opera开始支持Unicode 5.2之后,这会降低脚本的可用性。

5 个答案:

答案 0 :(得分:19)

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);
};

playground page

答案 1 :(得分: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);
};

更新

可能有一些方法可以加速上述正则表达式。使用具有延迟量词的否定字符类似乎有助于提高速度(在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);
};

答案 2 :(得分:2)

首先解决标题中的问题:

JavaScript中没有工具可用于访问字符的Unicode属性。您需要为此目的找到一个库或服务(我担心如果您需要可靠的东西可能会很困难)或者从Unicode字符“database”(特定格式的文本文件集合)中提取相关信息并编写自己的代码来使用它。

然后是留言体中的问题:

这似乎更加绝望。但是,对于知识渊博且知道Avestan的有限数量的用户而言,这可能是一件事,也许在正确的方向性上显示一串Avestan字符以及它们的图像并要求用户点击一下也不会太糟糕。如果订单错误,按钮。你可以将这个选择保存在一个cookie中,这样用户只需要这样做一次(每个浏览器;虽然它应该是相对短暂的cookie,因为浏览器可能会更新)。

答案 3 :(得分:2)

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

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>.

似乎有效。 :)

答案 4 :(得分:2)

希伯来语和阿拉伯语的测试(我知道唯一的现代RTL语言/字符集,从右到左流动,除了我没有研究过的任何与波斯语相关的内容):

/[\u0590-\u06FF]/.test(textarea.value)

更多的研究表明了以下几点:

/[\u0590-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]/.test(textarea.value)