在PHP中检测Unicode字符范围

时间:2013-12-20 23:16:06

标签: php unicode utf-8 character-encoding

晚上,

有没有人知道在PHP中检测字符串的Unicode范围的最快方法是什么?我以为在PHP中会有这样的事情,但我找不到任何东西。理想情况下我想要的是一个函数,可以说,'John Jones'的100%是拉丁语OR'Jonesјезик'是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

再次使用全拉丁语搜索,您将得到大约100,000,000个结果,而不是20,000。在这种情况下,希望在文本的上下文中适当地替换字符。这种检测有用的一个很好的例子是那些使用西里尔字母来绕过亵渎过滤器的人。

1 个答案:

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