统计外语中出现的字符数

9
有没有最佳方法来实现非英文字母的字符计数?例如,如果我们以英语单词"Mother"为例,它是一个6个字母的单词。但如果你用泰米尔语输入相同的单词(மதர்),它只有三个字母(ம+த+ர்),但系统会将最后一个字母(ர்)视为两个字符(ர+ஂ=ர்)。那么有没有办法计算真正的字符数呢?
一条线索是,如果我们在键盘上移动光标到单词(மதர்)中,它只会经过3个字母而不是4个被系统认为的字符,那么有没有办法通过这种方式找到解决方案呢?任何关于此的帮助都将不胜感激...

某种静态地图查找?只是出于好奇,你需要这个在哪里使用? - Vaibhav Desai
我猜这是一个相关的问题。也许不是...我只是在帮忙。 - Ron van der Heijden
3
这是一个棘手的问题。你可能需要首先进行规范分解(Normalization Form 'D')处理,这样看似相等的字符串才确实是相等的。然后检查有多少个扩展字形群集。很可能JavaScript有适用的库工具。(如果没有,也应该有)。 - DavidO
2个回答

9

更新

午饭回来了 =) 恐怕之前的方法在处理外语时效果不佳 因此我添加了另一个示例,可能是一种解决方法

var UnicodeNsm = [Array 1280] //It holds all escaped Unicode Non Space Marks
function countNSMString(str) {
    var chars = str.split("");
    var count = 0;
    for (var i = 0,ilen = chars.length;i<ilen;i++) {
      if(UnicodeNsm.indexOf(escape(chars[i])) == -1) {
        count++;
       }
    }
    return count;
}

var English = "Mother";  
var Tamil = "மதர்";
var Vietnamese = "mẹ"
var Hindi = "मां"

function logL (str) {    
      console.log(str + " has " + countNSMString(str) + " visible Characters and " + str.length + " normal Characters" ); //"மதர் has 3 visible Characters"
}

logL(English) //"Mother has 6 visible Characters and 6 normal Characters"
logL(Tamil) //"மதர் has 3 visible Characters and 4 normal Characters"
logL(Vietnamese) //"mẹ has 2 visible Characters and 3 normal Characters"
logL(Hindi) //"मां has 1 visible Characters and 3 normal Characters"

所以这只是检查字符串中是否有Unicode NSM字符,并忽略计数,这对大多数语言都有效,不仅限于泰米尔语, 而且一个有1280个元素的数组不应该成为性能问题。
这里是Unicode NSM的列表 http://www.fileformat.info/info/unicode/category/Mn/list.htm 这是相应的JSBin
经过对字符串操作进行一些实验后,结果发现String.indexOf对于 "ர""ர்" 返回值相同,即
"ர்ரர".indexOf("ர்") == "ர்ரர".indexOf("ர" + "்") //true 但是
"ர்ரர".indexOf("ர") == "ர்ரர".indexOf("ர" + "ர") //false

我借此机会尝试了类似以下的操作:

//ர்

var char = "ரர்ர்ரர்்";
var char2 = "ரரர்ர்ரர்்";    
var char3 = "ர்ரர்ர்ரர்்";

function countStr(str) {
         var  chars = str.split("");
         var count = 0;
          for(var i = 0, ilen = chars.length;i<ilen;i++) {
                 var chars2 = chars[i] + chars[i+1];   
                 if (str.indexOf(chars[i]) == str.indexOf(chars2))
                   i += 1;
               count++;
            }
         return count;
 }


console.log("--");

console.log(countStr(char)); //6

console.log(countStr(char2)); //7

console.log(countStr(char3)); //7

这似乎适用于上面的字符串,可能需要进行一些调整,因为我对编码等方面一无所知,但也许这是你可以开始的一个点。

这里是JSBin


嗨,Glutamat,这似乎是一个不错的解决方案。你能解释一下for循环内的IF条件吗? - Stranger
很棒的回答,Glutamat!它适用于许多情况。感谢您的巨大努力。再次感谢... - Stranger
“[Array 1280]” 这种语法叫什么? - palapapa

2
您可以使用此功能在计数计算中忽略组合标记:
function charCount( str ) {
    var re = /[\u0300-\u036f\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f\u0b82\u0b83\u0bbe\u0bbf\u0bc0-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7]/g
    return str.replace( re, "").length;
}

console.log(charCount('மதர்'))// 3

//More tests on random Tamil text:
//Paint the text character by character to verify, for instance 'யெ' is a single character, not 2

console.log(charCount("மெய்யெழுத்துக்கள்")); //9
console.log(charCount("ஒவ்வொன்றுடனும்")); //8
console.log(charCount("தமிழ்")); //3
console.log(charCount("வருகின்றனர்.")); //8
console.log(charCount("எழுதப்படும்")); //7

泰米尔语的符号和标记没有与其目标字符组成单个Unicode字符,因此规范化无法帮助。我已经手动添加了所有泰米尔组合标记或符号到正则表达式中,但它也包括普通组合标记的范围,因此charCount("ä")不管规范化形式都是1

嗨Esailija,对于泰米尔语来说它工作得很好。但是是否有适用于所有语言的好解决方案呢? - Stranger
@Udhay 是的,我只需要将它们添加到正则表达式中。 - Esailija
我不擅长正则表达式。所以你能否解释一下你在这里使用的正则表达式,这样我就可以用它来编写其他语言的代码了... - Stranger
1
@Udhay 它会剥离正则表达式中提到的代码点。例如,\u0300-\u036f 剥离了范围在 U+0300-U+036f 的所有代码点,而 \u0bd7 剥离了代码点 U+0bd7。这只是一个代码点范围和单个代码点的列表,不被考虑为字符计算。 - Esailija

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接