我有一个存储在MySQL数据库中的the Geonames database副本,以及一个允许用户在数据库中搜索其城市的PHP应用程序。如果他们用英语键入城市名称,它可以正常工作,但我希望他们能够用他们的母语搜索。
例如,他们应该能够搜索Tokyo
,而不是要求日语发音者搜索東京
。
Geonames数据库包含一个alternatenames
列,其中包含“alternatenames, comma separated, ascii names automatically transliterated, convenience attribute from alternatename table, varchar(10000)
。”
例如,alternatenames
行的Tokyo
值为Edo,TYO,Tochiu,Tocio,Tokija,Tokijas,Tokio,Tokió,Tokjo,Tokyo,Toquio,Toquio - dong jing,Toquio - æ±äº¬,Tòquio,Tókýó,Tóquio,TÅkyÅ,dokyo,dong jing,dong jing dou,tokeiyw,tokkiyo,tokyo,twkyw,twqyw,Τόκιο,Токио,Токё,Токіо,ÕÕ¸Õ¯Õ«Õ¸,טוקיו,توكيو,توکیو,طوكيو,ܛܘܟÜܘ,ܜܘܟÜܘ,टोकà¥à¤¯à¥‹,டோகà¯à®•à®¿à®¯à¯‹,โตเà¸à¸µà¸¢à¸§,ტáƒáƒ™áƒ˜áƒ,东京,æ±äº¬,æ±äº¬éƒ½,ë„ì¿„
。
这些值不完全包含東京
,但我猜它们包含一种已经以某种方式编码或转换的形式。所以,我假设如果我在搜索字符串上执行相同的编码/转换,那么我将能够匹配该行。例如:
mysql_query( sprintf( "
SELECT * FROM geoname
WHERE
MATCH( name, asciiname, alternatenames )
AGAINST ( %s )
LIMIT 1",
iconv( 'UTF-8', 'ASCII', '東京' )
) );
问题在于我不知道转换会是什么。我尝试过很多iconv()
,mb_convert_string()
等组合,但没有运气。
MySQL表如下所示:
CREATE TABLE `geoname` (
`geonameid` int(11) NOT NULL DEFAULT '0',
`name` varchar(200) DEFAULT NULL,
`asciiname` varchar(200) DEFAULT NULL,
`alternatenames` mediumtext,
`latitude` decimal(10,7) DEFAULT NULL,
`longitude` decimal(10,7) DEFAULT NULL,
`fclass` char(1) DEFAULT NULL,
`fcode` varchar(10) DEFAULT NULL,
`country` varchar(2) DEFAULT NULL,
`cc2` varchar(60) DEFAULT NULL,
`admin1` varchar(20) DEFAULT NULL,
`admin2` varchar(80) DEFAULT NULL,
`admin3` varchar(20) DEFAULT NULL,
`admin4` varchar(20) DEFAULT NULL,
`population` int(11) DEFAULT NULL,
`elevation` int(11) DEFAULT NULL,
`gtopo30` int(11) DEFAULT NULL,
`timezone` varchar(40) DEFAULT NULL,
`moddate` date DEFAULT NULL,
PRIMARY KEY (`geonameid`),
KEY `timezone` (`timezone`),
FULLTEXT KEY `namesearch` (`name`,`asciiname`,`alternatenames`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
有人能指出我正确的方向吗?
答案 0 :(得分:3)
当我下载the Japan file并设置这样的数据库时:
CREATE TABLE geonames (
geonameid SERIAL,
name varchar(200),
asciiname varchar(200),
alternatenames varchar(10000),
latitude float,
longitude float,
featureclass varchar(1),
featurecode varchar(10),
countrycode varchar(2),
cc2 varchar(200),
admin1code varchar(20),
admin2code varchar(80),
admin3code varchar(20),
admin4code varchar(20),
population BIGINT,
elevation INT,
dem INT,
timezone varchar(40),
modificationdate DATE
) CHARSET utf8mb4;
然后我load the data喜欢这样:
LOAD DATA INFILE '/tmp/JP.txt' INTO TABLE geonames CHARACTER SET utf8mb4;
然后选择它:
SELECT alternatenames FROM geonames WHERE geonameid=1850147\G
我明白了:
*************************** 1. row ***************************
alternatenames: Edo,TYO,Tochiu,Tocio,Tokija,Tokijas,Tokio,Tokió,Tokjo,Tokyo,Toquio,Toquio - dong jing,Toquio - 東京,Tòquio,Tókýó,Tóquio,Tōkyō,dokyo,dong jing,dong jing dou,tokeiyw,tokkiyo,tokyo,twkyw,twqyw,Τόκιο,Токио,Токё,Токіо,Տոկիո,טוקיו,توكيو,توکیو,طوكيو,ܛܘܟܝܘ,ܜܘܟܝܘ,टोक्यो,டோக்கியோ,โตเกียว,ტოკიო,东京,東京,東京都,도쿄
我也可以这样搜索:
SELECT name FROM geonames WHERE alternatenames LIKE '%,東京,%';
这是一个很长的说法:注意创建表时的charset声明。我相信这是您在创建数据库时未能做到的。
答案 1 :(得分:2)
推荐阅读:
https://www.joelonsoftware.com/articles/Unicode.html
http://kunststube.net/encoding/
就MySQL而言,最重要的是MySQL连接的 characterset 。这就是MySQL Server认为客户端在其通信中使用的字符集。
SHOW VARIABLES LIKE '%characterset%'
如果设置不正确,例如,客户端正在发送latin1(ISO-8859-1),但MySQL服务器认为它正在接收UTF8,反之亦然,那就有可能出现mojibake。
同样重要的是alternatenames
列的 characterset 。
处理多字节字符集的一个问题是PHP sprintf
函数。 PHP中的许多字符串处理函数都具有“mutlibyte”等价物,可正确处理包含多字节字符的字符串。
https://secure.php.net/manual/en/book.mbstring.php
不幸的是,没有内置mb_sprintf
功能。
有关PHP中字符串处理的更详细说明,包括多字节字符/字符集:
https://secure.php.net/manual/en/language.types.string.php#language.types.string.details
摘录:
最终,这意味着使用Unicode编写正确的程序取决于仔细避免不起作用的函数,并且很可能会破坏数据并使用行为正常的函数,通常来自intl和mbstring扩展。但是,使用可以处理Unicode编码的函数只是一个开始。无论语言提供什么功能,都必须了解Unicode规范。
此外,谷歌搜索“utf8一直到”可能会返回一些有用的注释。但请注意,这个咒语不是问题的灵丹妙药或灵丹妙药。
“MySQL参考手册”中提到的另一个可能的问题:
https://dev.mysql.com/doc/refman/5.7/en/fulltext-restrictions.html
13.9.5全文限制
中文和日文等表意语言没有单词分隔符。因此,内置全文本解析器无法确定单词在这些语言和其他此类语言中的开始和结束位置。
在MySQL 5.7.6中,提供了一个支持中文,日文和韩文(CJK)的基于字符的ngram全文解析器,以及一个支持日语的基于单词的MeCab解析器插件,用于InnoDB和MySIAM表。