2013-12-20 129 views
3

傍晚,在PHP中检测Unicode字符范围

有没有人有想法检测字符串的Unicode范围的最快方法是在PHP中?我认为在PHP中会有这样做,但我找不到任何东西。理想情况下,我想要的是一个函数,会说,'约翰琼斯'的100%是拉丁语或'琼斯језик'是50%拉丁文和50%西里尔文。

你可以用类似下面的ReEx做到这一点:

strA = 'John Jones'; 
$strB = 'Српски језик'; 
$strC = 'Հայաստանի Հանրապետություն'; 
preg_match('~[\p{Cyrillic}\p{Common}]+~u', $strB, $res); 

但这就需要检查,对每个范围,这似乎不是一个好主意。或者,你可以得到每个角色的unicode值,并检查它所在的范围。但我想可能有人已经做出了这样的事情。

编辑

要查看关于为什么这可能是有用的多一点的想法,在评论中指出,有些人有时会混在视觉上相同的拉丁和西里尔字母。例如这是克罗地亚搜索用西里尔字母“С”,其余的拉丁文:

https://www.google.am/search?q=%22%D0%A1roatia%22&aq=f&oq=%22%D0%A1roatia%22

搜索再次与全拉丁美洲,你会得到关于亿的结果,而不是20,000。在这种情况下,最好在文本的上下文中适当地替换字符。一个很好的例子表明,这种检测的有用之处在于使用西里尔字母来绕过亵渎过滤器的人。

+1

你试图解决什么问题,使你认为你需要知道哪个百分比的字符来自哪个unicode脚本块?例如,知道80%的字符来自拉丁文,20%来自拉丁文扩展A不会告诉你它是罗马尼亚语还是越南语。 –

+0

嗨, 我有一张人名表。其中有些是非拉丁字符,有些是混合的。我需要检测哪些是哪一个,像西里尔文那样的许多字母可以被音译,但是其他的如阿拉伯文不能,或者至少没有意义。此外,对于来自东欧,俄罗斯等国家的人来说,他们有时会使用与西班牙语字符完全相同的西里尔文字符,反之亦然,从而导致混合字符串。我将所有名称都转换为拉丁文,并且我需要上述数据,因此我可以知道如何将每个名称转换为拉丁文。 –

+0

为什么?只需存储UTF8而不转换为拉丁文。 2013年,几乎所有常见技术都支持它。 –

回答

1

我工作过的东西。这将检测每个角色的范围。我只是把亚美尼亚,拉丁和俄罗斯放在首位。如果其他人有这方面的需要,你需要从一个来源找到detectRanges函数的字符范围,如:http://jrgraphix.net/r/Unicode/我想看看是否有更好的方法来做这个部分。确保范围中的任何字母字符都是小写字母。

mb_internal_encoding("UTF-8"); 
echo header("Content-Type: text/html;charset=UTF-8", true); 

class DetectUnicodeRanges 
{ 
    function entityToUTF8($number) 
    { 
     if($number < 0) 
       return false; 

     # Replace ASCII characters 
     if($number < 128) 
       return chr($number); 

     # Replace illegal Windows characters 
     if($number < 160) 
     { 
      switch($number) 
      { 
       case 128: $conversion = 8364; break; 
       case 129: $conversion = 160; break; 
       case 130: $conversion = 8218; break; 
       case 131: $conversion = 402; break; 
       case 132: $conversion = 8222; break; 
       case 133: $conversion = 8230; break; 
       case 134: $conversion = 8224; break; 
       case 135: $conversion = 8225; break; 
       case 136: $conversion = 710; break; 
       case 137: $conversion = 8240; break; 
       case 138: $conversion = 352; break; 
       case 139: $conversion = 8249; break; 
       case 140: $conversion = 338; break; 
       case 141: $conversion = 160; break; 
       case 142: $conversion = 381; break; 
       case 143: $conversion = 160; break; 
       case 144: $conversion = 160; break; 
       case 145: $conversion = 8216; break; 
       case 146: $conversion = 8217; break; 
       case 147: $conversion = 8220; break; 
       case 148: $conversion = 8221; break; 
       case 149: $conversion = 8226; break; 
       case 150: $conversion = 8211; break; 
       case 151: $conversion = 8212; break; 
       case 152: $conversion = 732; break; 
       case 153: $conversion = 8482; break; 
       case 154: $conversion = 353; break; 
       case 155: $conversion = 8250; break; 
       case 156: $conversion = 339; break; 
       case 157: $conversion = 160; break; 
       case 158: $conversion = 382; break; 
       case 159: $conversion = 376; break; 
      } 

      return $conversion; 
     } 

     if ($number < 2048) 
       return chr(($number >> 6) + 192) . chr(($number & 63) + 128); 
     if ($number < 65536) 
       return chr(($number >> 12) + 224) . chr((($number >> 6) & 63) + 128) . chr(($number & 63) + 128); 
     if ($number < 2097152) 
       return chr(($number >> 18) + 240) . chr((($number >> 12) & 63) + 128) . chr((($number >> 6) & 63) + 128) . chr(($number & 63) + 128); 

     return false; 
    } 

    function MBStrToHexes($str) 
    {   
     $str = mb_convert_encoding($str, 'UCS-4BE'); 
     $hexs = array(); 
     for($i = 0; $i < mb_strlen($str, 'UCS-4BE'); $i++) 
     {   
      $s2 = mb_substr($str, $i, 1, 'UCS-4BE');      
      $val = unpack('N', $s2); 
      $hexs[] = str_pad(dechex($val[1]), 4, 0, STR_PAD_LEFT);     
     }   
     return($hexs); 
    } 

    function detectRanges($str) 
    { 
     $hexes = $this->MBStrToHexes($str); 
     foreach($hexes as $hex) 
     { 
      if(($hex >= '0041') && ($hex <= '024f')) 
       echo $this->entityToUTF8(hexdec($hex)) . ' - Latin<br />'; 
      elseif(($hex >= '0400') && ($hex <= '04ff')) 
       echo $this->entityToUTF8(hexdec($hex)) . ' - Cyrillic<br />'; 
      elseif(($hex >= '0530') && ($hex <= '058f')) 
       echo $this->entityToUTF8(hexdec($hex)) . ' - Armenian<br />'; 
      else 
       echo $this->entityToUTF8($hex) . ' - Some Other Range<br />'; 
     } 
    } 

} 

#$strB = 'Cornelius Trow'; 
$strB = 'Cornelius Српски Հայաստանի'; 
#$strB = 'Հայաստանի Հանրապետություն'; 
echo 'Testing String: ' . $strB . '<br />'; 
$dur = new DetectUnicodeRanges(); 
$dur->detectRanges($strB);