• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 将UCA检验添加到Unicode字符集

    本节介绍如何通过在MySQL 文件<collation><charset>字符集描述中写入元素来为Unicode字符集添加UCA校验Index.xml。此处描述的过程不需要重新编译MySQL。它使用语言环境数据标记语言(LDML)规范的子集,该规范可从 http://www.unicode.org/reports/tr35/获得。使用此方法,您无需定义整个校验规则。而是从现有的“基础”开始校验规则,并根据新校验规则与基本校验规则的不同之处进行描述。下表列出了可以定义UCA校验的Unicode字符集的基本校验。无法为创建用户定义的UCA校验utf16le。没有utf16le_unicode_ci校验规则可以作为此类校验规则的基础。

    表10.4可用于用户定义的UCA校验的MySQL字符集

    字符集基本校验
    utf8utf8_unicode_ci
    ucs2ucs2_unicode_ci
    utf16utf16_unicode_ci
    utf32utf32_unicode_ci

    以下各节说明如何添加使用LDML语法定义的校验规则,并提供MySQL支持的LDML规则的摘要。

    使用LDML语法定义UCA校验

    要在不重新编译MySQL的情况下为Unicode字符集添加UCA校验,请使用以下过程。如果您不熟悉用于描述校验规则的校验特征的LDML规则,请参见“ MySQL支持的LDML语法”。

    该示例将命名规则添加utf8_phone_ciutf8字符集。该校验是针对涉及Web应用程序的场景而设计的,用户在该Web应用程序中发布其姓名和电话号码。电话号码的格式可以非常不同:

    +7-12345-67
    +7-12-345-67
    +7 12 345 67
    +7 (12) 345 67
    +71234567
    

    通过处理这些类型的值引起的问题是,不同的允许格式使搜索特定电话号码变得非常困难。解决方案是定义一个新的校验规则,重新校验标点符号,使其可忽略。

    1. 选择一个校验ID,如“选择校验ID”所示。以下步骤使用ID 1029。
    2. 修改Index.xml配置文件。该文件位于character_sets_dir系统变量命名的目录中。尽管路径名称在您的系统上可能有所不同,但是您可以按以下方式检查变量值:

      mysql> SHOW VARIABLES LIKE 'character_sets_dir';
      +--------------------	+-----------------------------------------	+
      | Variable_name      	| Value                                   	|
      +--------------------	+-----------------------------------------	+
      | character_sets_dir 	| /user/local/mysql/share/mysql/charsets/ 	|
      +--------------------	+-----------------------------------------	+
      
    3. 选择校验规则的名称,并将其列出在Index.xml文件中。此外,您需要提供校验校验规则。找到<charset>要添加校验规则的字符集的<collation>元素,然后添加一个指示校验规则名称和ID 的元素,以将名称与ID关联。在<collation>元素内,提供一个<rules>包含校验规则的元素:

      <charset name="utf8">
        ...
        <collation name="utf8_phone_ci" id="1029">
          <rules>
            <reset>\u0000</reset>
            <i>\u0020</i> <!-- space -->
            <i>\u0028</i> <!-- left parenthesis -->
            <i>\u0029</i> <!-- right parenthesis -->
            <i>\u002B</i> <!-- plus -->
            <i>\u002D</i> <!-- hyphen -->
          </rules>
        </collation>
        ...
      </charset>
      
    4. 如果要对其他Unicode字符集使用类似的校验规则,请添加其他<collation>元素。例如,要定义ucs2_phone_ci,请向<collation>元素添加一个<charset >元素。请记住,每个校验规则必须具有自己的唯一ID。
    5. 重新启动服务器,并使用以下语句验证是否存在校验规则:

      mysql> SHOW COLLATION WHERE Collation = 'utf8_phone_ci';
      +---------------	+---------	+------	+---------	+----------	+---------	+
      | Collation     	| Charset 	| Id   	| Default 	| Compiled 	| Sortlen 	|
      +---------------	+---------	+------	+---------	+----------	+---------	+
      | utf8_phone_ci 	| utf8    	| 1029 	|         	|          	|       8 	|
      +---------------	+---------	+------	+---------	+----------	+---------	+
      

    现在测试校验规则以确保它具有所需的属性。

    使用新的校验规则创建一个包含一些示例电话号码的表:

    mysql> CREATE TABLE phonebook (
             name VARCHAR(64),
             phone VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_phone_ci
           );
    Query OK, 0 rows affected (0.09 sec)
    
    mysql> INSERT INTO phonebook VALUES ('Svoj','	+7 912 800 80 02');
    Query OK, 1 row affected (0.00 sec)
    
    mysql> INSERT INTO phonebook VALUES ('Hf','	+7 (912) 800 80 04');
    Query OK, 1 row affected (0.00 sec)
    
    mysql> INSERT INTO phonebook VALUES ('Bar','	+7-912-800-80-01');
    Query OK, 1 row affected (0.00 sec)
    
    mysql> INSERT INTO phonebook VALUES ('Ramil','(7912) 800 80 03');
    Query OK, 1 row affected (0.00 sec)
    
    mysql> INSERT INTO phonebook VALUES ('Sanja','	+380 (912) 8008005');
    Query OK, 1 row affected (0.00 sec)
    

    运行一些查询以参见是否实际上忽略了被忽略的标点符号以进行比较和校验:

    mysql> SELECT * FROM phonebook ORDER BY phone;
    +-------	+--------------------	+
    | name  	| phone              	|
    +-------	+--------------------	+
    | Sanja 	| 		+380 (912) 8008005 	|
    | Bar   	| 		+7	-912	-800	-80	-01   	|
    | Svoj  	| 		+7 912 800 80 02   	|
    | Ramil 	| (7912) 800 80 03   	|
    | Hf    	| 		+7 (912) 800 80 04 	|
    +-------	+--------------------	+
    5 rows in set (0.00 sec)
    
    mysql> SELECT * FROM phonebook WHERE phone='	+7(912)800-80-01';
    +------	+------------------	+
    | name 	| phone            	|
    +------	+------------------	+
    | Bar  	| 		+7	-912	-800	-80	-01 	|
    +------	+------------------	+
    1 row in set (0.00 sec)
    
    mysql> SELECT * FROM phonebook WHERE phone='79128008001';
    +------	+------------------	+
    | name 	| phone            	|
    +------	+------------------	+
    | Bar  	| 		+7	-912	-800	-80	-01 	|
    +------	+------------------	+
    1 row in set (0.00 sec)
    
    mysql> SELECT * FROM phonebook WHERE phone='7 9 1 2 8 0 0 8 0 0 1';
    +------	+------------------	+
    | name 	| phone            	|
    +------	+------------------	+
    | Bar  	| 		+7	-912	-800	-80	-01 	|
    +------	+------------------	+
    1 row in set (0.00 sec)
    

    MySQL支持的LDML语法

    本节介绍了MySQL可以识别的LDML语法。这是http://www.unicode.org/reports/tr35/上 LDML规范中描述的语法的子集,有关更多信息,请查阅该语法。MySQL可以识别语法的足够大的子集,在许多情况下,可以从Unicode Common Locale Data Repository下载校验规则定义并将相关部分(即<rules>and </rules>标记之间的部分)粘贴到MySQL中Index.xml文件。除了字符校验仅在主级别上进行之外,所有此处描述的规则均受支持。可以识别在次要或更高级别的分类上指定差异的规则(因此可以包含在校验定义中),但在主要级别上被视为相等。

    MySQL服务器在解析Index.xml文件时发现问题时,将生成诊断。请参见“ Index.xml解析期间的诊断”。

    字符表示

    LDML规则中命名的字符可以按原义或格式书写,其中十六进制Unicode代码点值。例如, and 可以字面形式或as 和编写。在十六进制值内,数字到不区分大小写。和相等。对于UCA 4.0.0校验,十六进制符号只能用于基本多语言平面中的字符,而不能用于BMP 到to的字符。对于UCA 5.2.0校验,十六进制符号可用于任何字符。\unnnnnnnnAá\u0041\u00E1AF\u00E1\u00e10000FFFF

    Index.xml文件本身应使用UTF-8编码写入。

    语法规则

    LDML具有重置规则和移位规则以指定字符顺序。顺序是作为一组规则给出的,这些规则以建立锚点的重置规则开始,然后是指示字符相对于锚点的校验方式的移位规则。

    • 一个<reset>规则并不在其本身指定任何次序。取而代之的是,它“重置”后续移位规则的顺序,以使它们相对于给定字符采用。以下规则中的任何一个重置与字母相关的后续移位规则'A'

      <reset>A</reset>
      
      <reset>\u0041</reset>
      
    • <p><s><t>换档规则定义从另一个字符的字符的伯,仲和叔胺的差异:

      • 使用主要差异来区分单独的字母。
      • 使用次要差异来区分重音变化。
      • 使用三次差异来区分字母大小写的变化。

      这些规则中的任何一个都指定了'G'字符的主要移位规则:

      <p>G</p>
      
      <p>\u0047</p>
      
    • <i>换档规则表示一个字符相同的校验到另一个。以下规则使'b'校验与'a'

      <reset>a</reset>
      <i>b</i>
      
    • 缩写移位语法使用一对标签指定多个移位规则。下表显示了缩写语法规则和等效的非缩写规则之间的对应关系。

      表10.5缩略移位语法

      缩写语法非缩写语法
      <pc>xyz</pc><p>x</p><p>y</p><p>z</p>
      <sc>xyz</sc><s>x</s><s>y</s><s>z</s>
      <tc>xyz</tc><t>x</t><t>y</t><t>z</t>
      <ic>xyz</ic><i>x</i><i>y</i><i>z</i>

    • 扩展是一种重置规则,可为多字符序列建立定位点。MySQL支持扩展2到6个字符。以下规则'z'在主要级别上要比三个字符的顺序大'abc'

      <reset>abc</reset>
      <p>z</p>
      
    • 收缩是对多字符序列进行校验的移位规则。MySQL支持2至6个字符长的收缩。以下规则'xyz'在主要级别上将三个字符的序列设置为大于'a'

      <reset>a</reset>
      <p>xyz</p>
      
    • 长膨胀和长收缩可以一起使用。这些规则使三个字符的序列'xyz'在主要级别上比三个字符的序列大'abc'

      <reset>abc</reset>
      <p>xyz</p>
      
    • 普通扩展语法使用<x>加号<extend>元素指定扩展。遵循以下规则,使角色'k'在次要级别上比序列更大'ch'。也就是说,'k'其行为就像是在'c'后面跟随一个字符扩展为一个字符'h'

      <reset>c</reset>
      <x><s>k</s><extend>h</extend></x>
      

      此语法允许长序列。这些规则'ccs'在第三级对序列的校验比对序列的校验大'cscs'

      <reset>cs</reset>
      <x><t>ccs</t><extend>cs</extend></x>
      

      LDML规范将普通扩展语法描述为“棘手的”。”以了解详细信息。

    • 先前的上下文语法使用<x>加号<context>元素来指定字符之前的上下文会影响其校验方式。以下规则'-'在二级放置比更大的规则'a',但仅在以下'-'情况下出现'b'

      <reset>a</reset>
      <x><context>b</context><s>-</s></x>
      
    • 先前的上下文语法可以包含<extend>元素。这些规则'def'在主要层级上具有比更大的规则'aghi',但仅在'def'出现'abc'以下情况时才具有:

      <reset>a</reset>
      <x><context>abc</context><p>def</p><extend>ghi</extend></x>
      
    • 重置规则允许一个before属性。通常,重设规则之后的移位规则表示在重设字符之后校验的字符。具有该before属性的重置规则之后的移位规则指示在重置字符之前校验的字符。以下规则将字符放在主要级别的'b'紧前面'a'

      <reset before="primary">a</reset>
      <p>b</p>
      

      允许的before属性值通过名称或等效数值指定校验级别:

      <reset before="primary">
      <reset before="1">
      
      <reset before="secondary">
      <reset before="2">
      
      <reset before="tertiary">
      <reset before="3">
      
    • 重置规则可以命名逻辑重置位置,而不是文字字符:

      <first_tertiary_ignorable/>
      <last_tertiary_ignorable/>
      <first_secondary_ignorable/>
      <last_secondary_ignorable/>
      <first_primary_ignorable/>
      <last_primary_ignorable/>
      <first_variable/>
      <last_variable/>
      <first_non_ignorable/>
      <last_non_ignorable/>
      <first_trailing/>
      <last_trailing/>
      

      这些规则'z'在主要级别上比具有默认Unicode校验规则元素表(DUCET)条目且不是CJK的不可忽略字符要大:

      <reset><last_non_ignorable/></reset>
      <p>z</p>
      

      逻辑位置具有下表中显示的代码点。

      表10.6逻辑复位位置代码点

      逻辑位置Unicode 4.0.0代码点Unicode 5.2.0代码点
      <first_non_ignorable/>U + 02D0U + 02D0
      <last_non_ignorable/>U + A48CU + 1342E
      <first_primary_ignorable/>U + 0332U + 0332
      <last_primary_ignorable/>U + 20EAU + 101FD
      <first_secondary_ignorable/>U + 0000U + 0000
      <last_secondary_ignorable/>U + FE73U + FE73
      <first_tertiary_ignorable/>U + 0000U + 0000
      <last_tertiary_ignorable/>U + FE73U + FE73
      <first_trailing/>U + 0000U + 0000
      <last_trailing/>U + 0000U + 0000
      <first_variable/>U + 0009U + 0009
      <last_variable/>U + 2183U + 1D371

    • <collation>元素允许一个shift-after-method属性,该属性会影响移位规则的字符权重计算。该属性具有以下允许值:

      • simple:按照没有before属性的重置规则计算字符权重。如果未提供该属性,则为默认设置。
      • expand:将扩展名用于重置规则后的班次。

      假设'0'和的'1'权重为0E29和,0E2A并且我们要将所有基本拉丁字母放在'0'和之间'1'

      <reset>0</reset>
      <pc>abcdefghijklmnopqrstuvwxyz</pc>
      

      对于简单换档模式,权重计算如下:

      'a' has weight 0E29	+1
      'b' has weight 0E29	+2
      'c' has weight 0E29	+3
      ...
      

      但是,没有足够的空缺位置在'0'和之间放置26个字符'1'。结果是数字和字母混合在一起。

      要解决此问题,请使用shift-after-method="expand"。然后按以下方式计算权重:

      'a' has weight [0E29][233D	+1]
      'b' has weight [0E29][233D	+2]
      'c' has weight [0E29][233D	+3]
      ...
      

      233D是character的UCA 4.0.0权重0xA48C,它是最后一个不可忽略的字符(校验规则中一种最大的字符,不包括CJK)。UCA 5.2.0与之类似,但3ACA用于字符0x1342E

    MySQL特定的LDML扩展

    LDML规则的扩展允许<collation>元素version<collation>标签中包括可选属性,以指示校验规则所基于的UCA版本。如果version省略该属性,则其默认值为4.0.0。例如,此规范指示基于UCA 5.2.0的校验:

    <collation id="nnn" name="utf8_xxx_ci" version="5.2.0">
    ...
    </collation>
    

    解析Index.xml期间的诊断

    MySQL服务器在解析Index.xml文件时发现问题时会生成诊断:

    • 未知标签将写入错误日志。例如,如果校验规则定义包含<aaa>标签,则会产生以下消息:

      [Warning] Buffered warning: Unknown LDML tag:
      'charsets/charset/collation/rules/aaa'
      
    • 如果无法进行校验初始化,则服务器将报告“ Unknown collation ”错误,并生成警告,说明问题所在,例如前面的示例。在其他情况下,当校验规则描述通常是正确的但包含一些未知标签时,则该校验规则将被初始化并可使用。未知部分将被忽略,但在错误日志中会生成警告。
    • 校验规则问题会生成警告,客户可以使用来显示警告SHOW WARNINGS。假设重置规则包含的扩展超过了支持的最大长度6个字符:

      <reset>abcdefghi</reset>
      <i>x</i>
      

      尝试使用校验会产生警告:

      mysql> SELECT _utf8'test' COLLATE utf8_test_ci;
      ERROR 1273 (HY000): Unknown collation: 'utf8_test_ci'
      mysql> SHOW WARNINGS;
      +---------	+------	+----------------------------------------	+
      | Level   	| Code 	| Message                                	|
      +---------	+------	+----------------------------------------	+
      | Error   	| 1273 	| Unknown collation: 'utf8_test_ci'      	|
      | Warning 	| 1273 	| Expansion is too long at 'abcdefghi=x' 	|
      +---------	+------	+----------------------------------------	+