簡體   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