Javascript toLowerCase奇怪的行为

时间:2013-12-15 23:55:35

标签: javascript unicode

我有一个小应用程序读取推文并尝试匹配关键字,我注意到这个特殊字符串的奇怪行为:

var text = "The Νіk​е D​un​k​ Ніgh ЅΒ 'Uglу Ѕwеаt​еr​' іѕ n​оw аvаіlаblе http://swoo.sh/IHVaTL";
var lowercase = text.toLowerCase()

现在小写的值是:

  

un un''''''''''l l l l l   http://swoo.sh/ihvatl

所以看起来字符串是一种奇怪的格式,我仔细检查了一些字母并发现:

text.charAt(4)
>"N"
text.charCodeAt(5)
>925
'N'.charCodeAt(0)
>78

因此,即使它看起来像普通的N,与之关联的unicode也对应于

  

0925थDEVANAGARI LETTER THA

根据unicode chart

所以我对如何发生这种情况感到有点疑惑,如果有反正“转换”到所谓的真实信件

2 个答案:

答案 0 :(得分:2)

有一个名为unidecode的python库,我曾经在python中解决过这个问题,它基本上将unicode“扁平化”为ascii。

快速谷歌显示,similar库可用于JavaScript。

答案 1 :(得分:1)

您可以创建一个单独的画布,每个拉丁字母,大写和小写,以进行比较。每次遇到不在Latin-1范围内的角色时,为其创建一个新画布,并使用image diff算法将其与每个拉丁字母字符进行比较。用最接近的匹配替换非拉丁字符。

例如:

var latinize = (function () {
    var latinLetters = [],
        canvases = [],
        size = 16,
        halfSize = size >> 1;

    function makeCanvas(chr) {
        var canvas = document.createElement('canvas'),
            context = canvas.getContext('2d');

        canvas.width = size;
        canvas.height = size;
        context.textBaseline = 'middle';
        context.textAlign = 'center';
        context.font = (halfSize) + "px sans-serif";
        context.fillText(chr, halfSize, halfSize);

        return context;
    }

    function nextChar(chr) {
        return String.fromCharCode(chr.charCodeAt(0) + 1);
    }

    function setupRange(from, to) {
        for (var chr = from; chr <= to; chr = nextChar(chr)) {
            latinLetters.push(chr);
            canvases.push(makeCanvas(chr));
        }
    }

    function calcDistance(ctxA, ctxB) {
        var distance = 0,
            dataA = ctxA.getImageData(0, 0, size, size).data,
            dataB = ctxB.getImageData(0, 0, size, size).data;

        for (var i = dataA.length; i--;) {
            distance += Math.abs(dataA[i] - dataB[i]);
        }

        return distance;
    }

    setupRange('a', 'z');
    setupRange('A', 'Z');
    setupRange('', ''); // ignore blank characters

    return function (text) {
        var result = "",
            scores, canvas;

        for (var i = 0; i < text.length; i++) {
            if (text.charCodeAt(i) < 128) {
                result += text.charAt(i);
                continue;
            }
            scores = [];
            canvas = makeCanvas(text.charAt(i));
            for (var j = 0; j < canvases.length; j++) {
                scores.push({
                    glyph: latinLetters[j],
                    score: calcDistance(canvas, canvases[j])
                });
            }
            scores.sort(function (a, b) {
                return a.score - b.score;
            });
            result += scores[0].glyph;
        }

        return result;
    }
}());

这会将您的测试字符串翻译为“nike dunk high sb'丑陋的毛衣'现已推出。”

另一种方法是创建一个巨大的数据结构,将所有相似的字符映射到它们的Latin-1等价物,就像@ willy的答案中的库一样。这对于“浏览器JavaScript”来说非常沉重,并且可能不适合发送到客户端,正如您可以通过查看该项目的来源看到的那样。

http://jsfiddle.net/Ly5Lt/4/