2013-05-11 17 views
16

Używam tabel mysql zestawu znaków utf8 na serwerze mysql 5.1, który nie obsługuje kodowania utf8mb4 w tabelach. Podczas wstawiania 4-bajtowych zakodowanych znaków utf8, takich jak "","","","","","唧","". Tabela wyświetli komunikat o błędzie lub pominie następujące teksty.Czy php wykrywa 4-bajtowe kodowane znaki utf8?

Jak mogę programowo wykryć 4-bajtowe kodowane znaki utf8 w PHP i zamienić je?

+0

Dość prosta: podzielić ciąg znaków (przez wiele sposobów, aby to zrobić) i sprawdzić, czy 'strlen ($ char) == 4'. Nie jestem pewien, czy jest to naprawdę poprawny sposób wykrywania znaków, których MySQL nie może obsłużyć, przejście przez punkt kodowy może być dokładniejsze. – deceze

+0

Czy sprawdziłeś rozszerzenie [wielobajtowe] (http://php.net/mbstring)? Pamiętaj też, aby zawsze [czytać komentarze] (http://dk1.php.net/manual/en/function.mb-internal-encoding.php#66568). –

+0

@deceze To podejście. Pójdę na to, jeśli nie ma innych eleganckich sposobów. –

Odpowiedz

13

Poniższe wyrażenie regularne zastąpi 4-bajtowych znaków UTF-8:

function replace4byte($string, $replacement = '') { 
    return preg_replace('%(?: 
      \xF0[\x90-\xBF][\x80-\xBF]{2}  # planes 1-3 
     | [\xF1-\xF3][\x80-\xBF]{3}   # planes 4-15 
     | \xF4[\x80-\x8F][\x80-\xBF]{2}  # plane 16 
    )%xs', $replacement, $string);  
} 

var_dump(replace4byte('d'), replace4byte('dd')); 

nie polegać na modyfikatora /u, więc nie ma potrzeby martwić się o UTF-8 do bycia PCRE wkompilowane. Jeśli jednak masz takie wsparcie, deceze to preg_replace_callback.

(Regex adaptacją Ensuring valid utf-8 in PHP)

13

ta powinna działać:

if (max(array_map('ord', str_split($string))) >= 240) 

Racjonalne jest, że kod wskazuje włącznie U + FFFF są kodowane w postaci trzech bajtów postaci 1110xxxx 10xxxxxx 10xxxxxx. Wyższe punkty kodowe mają postać 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx, tj. Najwyższy bajt ma wartość 240 lub wyższą. Jeśli w łańcuchu są takie bajty, jest to wskaźnik dla sekwencji 4-bajtowej.

Jeśli chcesz usunąć długie znaków, to zrobi:

preg_replace_callback('/./u', function (array $match) { 
    return strlen($match[0]) >= 4 ? null : $match[0]; 
}, $string) 

Choć nie może być bardziej elegancki sposób regex bezpośrednio wyrazić wysokie codepoints.

+0

Dziękujemy za wykroczenie, ale czy możesz je również zastąpić przykładem zastępczym? $ a = "omg, nie mogę wstawić do mojego stołu, blahblahblah"; // cel $ a == "omg, nie mogę wstawić MYTEXT do mojego stołu, blahblahblah"; –

Powiązane problemy