[英]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擴展的Collator :: 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 / collation(后者在您的情況下幾乎不相關)。
另一方面,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.