搜索阿拉伯语名称会丢弃mysql中“أ”,“ا”之间的差异

时间:2017-04-17 00:53:42

标签: php mysql search arabic

我在我的数据库中存储阿拉伯语名称。在阿拉伯语中,有些字母可能以不同的格式书写,例如“ا”,“أ”,“آ”,它们都代表相同的字母。另外,“ه”,“É”。

我需要在数据库中搜索名称并忽略“ا”,“أ”,“آ”之间的差异以及“ه”,“É”之间的差异。

所以,例如当用户进入搜索框“اسامة”时,它应该返回“أسامة”,“اسامة”,“أسامه”,“اسامه...”等。另一个例子,“فايز”,“فائز”应该返回

我怎么能用mysql查询呢?我如何搜索不同名称的相似名称?

我尝试使用Like关键字,但它无效。

{{1}}

2 个答案:

答案 0 :(得分:3)

我要处理的方法是规范化存储在数据库中的数据。在数据库中创建一个新字段,并运行一个脚本来规范化名称并将标准化版本保存在新字段中。因此,例如,“أسامة”,“اسامة”,“أسامه”,“اسامه”将在标准化字段中保存为اسامه,您将在规范化字段而不是原始名称字段上运行查询。

答案 1 :(得分:2)

更新:如果有人需要解决方案并且遇到这个问题,我会重写我的答案。

我知道这个问题有三种可能的解决方案:

  1. 创建自定义归类
  2. 添加标准化字段
  3. 在查询中使用正则表达式
  4. 我写了一篇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,并选择了1029custom 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文件(例如,如果您使用共享主机),添加标准化字段将是此解决方案在某些情况下,您可能会发现正则表达式有用。