我在我的数据库中存储阿拉伯语名称。在阿拉伯语中,有些字母可能以不同的格式书写,例如“ا”,“أ”,“آ”,它们都代表相同的字母。另外,“ه”,“É”。
我需要在数据库中搜索名称并忽略“ا”,“أ”,“آ”之间的差异以及“ه”,“É”之间的差异。
所以,例如当用户进入搜索框“اسامة”时,它应该返回“أسامة”,“اسامة”,“أسامه”,“اسامه...”等。另一个例子,“فايز”,“فائز”应该返回
我怎么能用mysql查询呢?我如何搜索不同名称的相似名称?
我尝试使用Like关键字,但它无效。
{{1}}
答案 0 :(得分:3)
我要处理的方法是规范化存储在数据库中的数据。在数据库中创建一个新字段,并运行一个脚本来规范化名称并将标准化版本保存在新字段中。因此,例如,“أسامة”,“اسامة”,“أسامه”,“اسامه”将在标准化字段中保存为اسامه,您将在规范化字段而不是原始名称字段上运行查询。
答案 1 :(得分:2)
更新:如果有人需要解决方案并且遇到这个问题,我会重写我的答案。
我知道这个问题有三种可能的解决方案:
我写了一篇tutorial,展示了如何将这些解决方案应用于MySQL。我将尝试在此总结这些步骤。
<强> 1。创建自定义归类
您可以创建自定义归类,使MySQL将这些字符作为一个处理。可以将自定义归类添加到位于charsets目录中的名为Index.xml
的文件中。可以通过使用以下内容查询information_schema
来找到文件的位置:
SHOW VARIABLES LIKE 'character_sets_dir';
导航到目录,备份文件,打开文件并滚动到元素<charset name=”utf8″>
,添加以下XML:
<charset name="utf8">
.
.
.
<collation name="utf8_arabic_ci" id="1029">
<rules>
<reset>\u0627</reset> <!-- Alef 'ا' -->
<i>\u0623</i> <!-- Alef With Hamza Above 'أ' -->
<i>\u0625</i> <!-- Alef With Hamza Below 'إ' -->
<i>\u0622</i> <!-- Alef With Madda Above 'آ' -->
</rules>
<rules>
<reset>\u0629</reset> <!-- Teh Marbuta 'ة' -->
<i>\u0647</i> <!-- Heh 'ه' -->
</rules>
<rules>
<reset>\u0000</reset> <!-- Ignore Tashkil -->
<i>\u064E</i> <!-- Fatha 'َ' -->
<i>\u064F</i> <!-- Damma 'ُ' -->
<i>\u0650</i> <!-- Kasra 'ِ' -->
<i>\u0651</i> <!-- Shadda 'ّ' -->
<i>\u064F</i> <!-- Sukun 'ْ' -->
<i>\u064B</i> <!-- Fathatan 'ً' -->
<i>\u064C</i> <!-- Dammatan 'ٌ' -->
<i>\u064D</i> <!-- Kasratan 'ٍ' -->
</rules>
</collation>
</charset>
这个xml只是说这个排序规则是utf8字符集之一,我选择将其命名为utf8_arabic_ci
,并选择了1029
,custom collations ids are in the range 1024-2047的标识号。整理规则告诉MySQL将所有形式的Alef视为同一个角色,以及Teh和Heh,并完全忽略tashkil。如果您愿意,可以添加更多规则。请参阅MySQL docuemntation for more info about custom collations。
现在重新启动MySQL并使用以下查询将列的排序规则更改为新的排序规则:
ALTER TABLE persons MODIFY name VARCHAR(50)
CHARACTER SET 'utf8' COLLATE 'utf8_arabic_ci';
你应该能够搜索'اسامة'并获得'اسامة','أسامه','أسامة'等等。
<强> 2。添加标准化字段
此解决方案需要向表中添加新字段。该字段将被“标准化”,这是标准化的阿拉伯语名字字段的示例:
id normalized_name name
1 احمد احمد
2 أحمد احمد
3 أسامه اسامة
4 أسامة اسامة
5 اسامه اسامة
6 اسَامه اسامة
这个规范化的字段可以通过向表中添加一个新列并使用“规范化”函数的结果来填充它,该函数用一个字符替换字符的不同变体并删除Tashkil。现在,为了使搜索查询起作用,我们将查询规范化字段并显示原始字段。如下所示:
SELECT name FROM persons WHERE normalized_name = "اسامة";
+--------------+
| name |
+--------------+
| أسامه |
| أسامة |
| اسامه |
| اسَامه |
+--------------+
第3。在查询中使用正则表达式
我不建议使用此解决方案,您将失去索引的优势,会降低性能,并且您将很难生成正则表达式模式。但是您可能会发现它对测试或特殊查询很有用。
您可以在MySQL查询中使用REGEX
或其同义词RLIKE
。例如,如果您想使用Alef的任何变体找到名称'أحمد',您将使用如下模式:
SELECT name FROM clients WHERE name REGEXP 'ا|أ|إ]حمد]'
这应显示所需的结果,您所要做的就是编写一个函数来为搜索字符串生成此模式。这是一个示例函数,但请记住,这只是一个示例,并不适用于所有情况:
// Add all your patterns and replacement in these arrays
$patterns = array( "/(ا|أ|آ)/", "/(ه|ة)/" );
$replacements = array( "[ا|أ|آ]", "[ة|ه]" );
$query_string = preg_replace($patterns, $replacements, $search_string);
这适用于Alef,Teh和Heh,但它不适用于Tashkil。
<强>结论强>
添加自定义排序规则我认为对于大多数情况来说是最佳解决方案,但您可能无法编辑charset文件(例如,如果您使用共享主机),添加标准化字段将是此解决方案在某些情况下,您可能会发现正则表达式有用。