繁体   English   中英

PHP mysql土耳其字符编码和比较

[英]PHP mysql turkish character encoding and comparison

我试图通过AJAX POST从MySql数据库中过滤土耳其语名称,英语字母单词列出一切正常但是如果我发送Ö(带字母的字母O)结果来自O和Ö不仅Ö

另外我注意到的是AJAX帖子是发送Ö%C3%96,任何人都可以帮忙吗?

请稍微冗长一点。
让我们从你的第二个问题开始。 %C3%96表示发送字节0xC3和0x96。 这两个字节在utf-8中编码字符Ö
从这一点(以及你的查询产生描述的结果)我假设你一直在使用utf-8

给定字符集的字符的字典顺序由所使用的校对确定。
这或多或少是一个有序的字符列表。 例如A,B,C,D,....意思是A<B<C ....
但是这些列表我在同一个“位置”包含多个字符,例如
[A,Ä],B,C,D ....意思是A==Ä->true

___短途旅行,与您的问题没有直接关系____
让我们来看看角色Ö的“名字”,这是LATIN CAPITAL LETTER O WITH DIAERESIS
所以,基本字符是O,它只是有一些装饰。
某些系统/库允许您指定比较的“粒度”/级别/强度,请参阅例如php-intl扩展的Collat​​or :: setStrength

<?php
// utf8 characters
define('SMALL_O_WITH_DIAERESIS', chr(0xC3) . chr(0xB6));
define('CAP_O_WITH_DIAERESIS', chr(0xC3) . chr(0x96));

$coll = collator_create( 'utf-8' );
foreach( array('PRIMARY', 'SECONDARY', 'TERTIARY') as $strength) {
    echo $strength, "\r\n";
    $coll->setStrength( constant('Collator::'.$strength) );
    echo '  o ~ ö = ', $coll->compare('o', SMALL_O_WITH_DIAERESIS), "\r\n";
    echo '  Ö ~ ö = ', $coll->compare(CAP_O_WITH_DIAERESIS, SMALL_O_WITH_DIAERESIS), "\r\n";
}

版画

PRIMARY
  o ~ ö = 0
  Ö ~ ö = 0
SECONDARY
  o ~ ö = -1
  Ö ~ ö = 0
TERTIARY
  o ~ ö = -1
  Ö ~ ö = 1

在初级阶段,所有涉及的字符(o,O,ö,Ö)只是字符O的一些无关变体,因此所有字符都被认为是相等的。
在二级,考虑到WITH DIAERESIS的附加“特征”,在第三级也考虑它是小写还是大写字母。
但是...... MySQL并没有完全按照这种方式工作......所以,再次抱歉;-)
___游览结束____

在MySQL中,有一些用于指定顺序的排序规则表。 当您选择一个字符集时,您还要隐含地选择该字符集的默认排序规则,除非您明确指定一个字符集。 在你的情况下,隐含选择的排序规则可能是utf8_general_ci ,它对待ö== o。
这适用于表格定义和连接的charset / collat​​ion(后者在您的情况下几乎不相关)。
另一方面,utf8_turkish_ci对待ö!= o。 这可能是你想要的整理。

当你有一个像表定义

CREATE TABLE soFoo (
  x varchar(32)
)
CHARACTER SET utf8

选择utf8的默认排序规则 - > general_ci - > o =ö
您可以在定义表时指定表的默认排序规则

CREATE TABLE soFoo (
  x varchar(32)
)
CHARACTER SET utf8 COLLATE utf8_turkish_ci

由于您已经有一个表加数据,您可以更改表的排序规则...但如果您在表级别执行此操作,则必须使用ALTER TABLE ... CONVERT (如果您使用MODIFY,则该列保留其“原始”整理)。

ALTER TABLE soFoo CONVERT TO CHARACTER SET utf8 COLLATE utf8_turkish_ci

这应该照顾你的问题。


作为旁注,还有(如上所述) 分配给您的连接排序规则 选择字符集意味着选择排序规则。 当(直接)连接到MySQL时,我主要使用PDO ,我的默认连接代码如下所示

$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
    PDO::ATTR_EMULATE_PREPARES=>false,
    PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
    PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));

请注意charset=utf8 ; 没有排序规则,所以再次将general_ci分配给连接。 这就是原因

<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'localonly', 'localonly', array(
    PDO::ATTR_EMULATE_PREPARES=>false,
    PDO::MYSQL_ATTR_DIRECT_QUERY=>false,
    PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION
));

$smallodiaresis_utf8 = chr(0xC3) . chr(0xB6);
foreach( $pdo->query("SELECT 'o'='$smallodiaresis_utf8'") as $row ) {
    echo $row[0];
}

打印1意思是o ==ö。 语句中使用的字符串文字被视为utf8 / utf8_general_ci。

我可以在语句中明确指定字符串文字的排序规则

SELECT 'o' COLLATE utf8_turkish_ci ='ö'

(仅为两个文字/操作数之一设置;为什么以及如何工作,请参阅表达式的排序
或者我可以通过设置连接校对

$pdo->exec("SET collation_connection='utf8_turkish_ci'");

两者都导致了

foreach( $pdo->query("SELECT 'o'[...]='$smallodiaresis_utf8'") as $row ) {
    echo $row[0];
}

印刷0

编辑:并使事情进一步复杂化:
字符集utf8不能代表所有可能的字符。 有一个更广泛的字符集utf8mb4

PHP代码应该接收%C3%96适当地解码回Ö 但如果没有,那么将PHP函数urldecode()应用于字符串。

你仍然会有角色Ö ,而不是O ; 这可以吗?

如果你得到Ö ,那么就有utf8和latin1的混合物。 这是一个不同的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM