Düzgün görüntülenmeyen utf8 olmayan karakterleri dizeden kaldırma konusunda sorun yaşıyorum. Karakterler şuna benzer 0x97 0x61 0x6C 0x6F (onaltılık gösterim)
Bunları kaldırmanın en iyi yolu nedir? Normal ifade mi yoksa başka bir şey mi?
Düzgün görüntülenmeyen utf8 olmayan karakterleri dizeden kaldırma konusunda sorun yaşıyorum. Karakterler şuna benzer 0x97 0x61 0x6C 0x6F (onaltılık gösterim)
Bunları kaldırmanın en iyi yolu nedir? Normal ifade mi yoksa başka bir şey mi?
Yanıtlar:
Bir normal ifade yaklaşımı kullanma:
$regex = <<<'END'
/
(
(?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3
){1,100} # ...one or more times
)
| . # anything else
/x
END;
preg_replace($regex, '$1', $text);
UTF-8 dizilerini arar ve bunları grup 1'de yakalar. Ayrıca UTF-8 dizisinin parçası olarak tanımlanamayan tek baytlarla eşleşir, ancak bunları yakalamaz. Değiştirme, grup 1'de yakalanan şeydir. Bu, tüm geçersiz baytları etkili bir şekilde kaldırır.
Geçersiz baytları UTF-8 karakterleri olarak kodlayarak dizeyi onarmak mümkündür. Ancak hatalar rastgele ise, bu bazı garip semboller bırakabilir.
$regex = <<<'END'
/
(
(?: [\x00-\x7F] # single-byte sequences 0xxxxxxx
| [\xC0-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
| [\xE0-\xEF][\x80-\xBF]{2} # triple-byte sequences 1110xxxx 10xxxxxx * 2
| [\xF0-\xF7][\x80-\xBF]{3} # quadruple-byte sequence 11110xxx 10xxxxxx * 3
){1,100} # ...one or more times
)
| ( [\x80-\xBF] ) # invalid byte in range 10000000 - 10111111
| ( [\xC0-\xFF] ) # invalid byte in range 11000000 - 11111111
/x
END;
function utf8replacer($captures) {
if ($captures[1] != "") {
// Valid byte sequence. Return unmodified.
return $captures[1];
}
elseif ($captures[2] != "") {
// Invalid byte of the form 10xxxxxx.
// Encode as 11000010 10xxxxxx.
return "\xC2".$captures[2];
}
else {
// Invalid byte of the form 11xxxxxx.
// Encode as 11000011 10xxxxxx.
return "\xC3".chr(ord($captures[3])-64);
}
}
preg_replace_callback($regex, "utf8replacer", $text);
DÜZENLE:
!empty(x)
boş olmayan değerlerle eşleşir ( "0"
boş kabul edilir).x != ""
dahil boş olmayan değerlerle eşleşecek "0"
.x !== ""
dışında herhangi bir şeyle eşleşecek ""
.x != ""
Bu durumda kullanmak için en iyisi gibi görünüyor.
Maçı da biraz hızlandırdım. Her karakteri ayrı ayrı eşleştirmek yerine, geçerli UTF-8 karakter dizileriyle eşleşir.
$regex = <<<'END'
PHP <5.3.x için ne kullanılmalı ?
elseif (!empty($captures([2])) {
ve !== ""
boş "0"
kabul edildiği için boş yerine kullanmalısınız . Ayrıca bu işlev çok yavaştır, bu daha hızlı yapılabilir mi?
utf8_encode()
Zaten bir UTF8 dizesine uygularsanız , bozuk bir UTF8 çıktısı döndürür.
Tüm bu konuları ele alan bir fonksiyon yaptım. Denir Encoding::toUTF8()
.
Dizelerinizin kodlamasının ne olduğunu bilmenize gerek yok. Latin1 (ISO8859-1), Windows-1252 veya UTF8 olabilir veya dize bunların bir karışımına sahip olabilir. Encoding::toUTF8()
her şeyi UTF8'e dönüştürür.
Bunu yaptım çünkü bir hizmet bana tamamen karışmış bir veri beslemesi veriyordu, bu kodlamaları aynı dizede karıştırıyordu.
Kullanımı:
require_once('Encoding.php');
use \ForceUTF8\Encoding; // It's namespaced now.
$utf8_string = Encoding::toUTF8($mixed_string);
$latin1_string = Encoding::toLatin1($mixed_string);
Başka bir işlev, Encoding :: fixUTF8 () ekledim, bu işlev, UTF8'e birden çok kez kodlanmış olan bozuk ürün gibi görünen her UTF8 dizesini düzeltir.
Kullanımı:
require_once('Encoding.php');
use \ForceUTF8\Encoding; // It's namespaced now.
$utf8_string = Encoding::fixUTF8($garbled_utf8_string);
Örnekler:
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
çıktı:
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
İndir:
Mbstring'i kullanabilirsiniz:
$text = mb_convert_encoding($text, 'UTF-8', 'UTF-8');
... geçersiz karakterleri kaldıracak.
<0x1a>
<0x1a>
, basılabilir karakter olmasa da, tamamen geçerli bir UTF-8 dizisi. Yazdırılamayan karakterlerle ilgili sorunlarınız olabilir mi?
ini_set('mbstring.substitute_character', 'none');
aksi takdirde sonuçta soru işaretleri alıyordum.
Bu işlev tüm ASCII OLMAYAN karakterleri kaldırır, yararlıdır, ancak soruyu çözmez:
Bu, kodlamadan bağımsız olarak her zaman çalışan işlevimdir:
function remove_bs($Str) {
$StrArr = str_split($Str); $NewStr = '';
foreach ($StrArr as $Char) {
$CharNo = ord($Char);
if ($CharNo == 163) { $NewStr .= $Char; continue; } // keep £
if ($CharNo > 31 && $CharNo < 127) {
$NewStr .= $Char;
}
}
return $NewStr;
}
Nasıl çalışır:
echo remove_bs('Hello õhowå åare youÆ?'); // Hello how are you?
í
adres alanında geçerli bir UTF-8 karakteri olan karakterdi, tabloya bakınız . Moral: API hata mesajlarına güvenmeyin :)
$text = iconv("UTF-8", "UTF-8//IGNORE", $text);
Ben bunu kullanıyorum. Oldukça iyi çalışıyor gibi görünüyor. Alındığı http://planetozh.com/blog/2005/01/remove-invalid-characters-in-utf-8/
bunu dene:
$string = iconv("UTF-8","UTF-8//IGNORE",$string);
İconv kılavuzuna göre , işlev ilk parametreyi giriş karakter kümesi olarak, ikinci parametreyi çıkış karakter kümesi olarak ve üçüncüyü gerçek girdi dizesi olarak alacaktır.
Hem girdi hem de çıktı karakter kümesini UTF-8 olarak ayarlarsanız ve //IGNORE
bayrağı çıktı karakter kümesine eklerseniz , işlev, girdi dizesindeki çıktı karakter kümesiyle temsil edilemeyen tüm karakterleri çıkarır (ayırır). Bu nedenle, giriş dizesini filtrelemek etkin.
iconv
. @halfer Belki giriş verileriniz utf-8'den değildir. Diğer bir seçenek de ascii'ye yeniden dönüştürme yapmak ve ardından tekrar utf-8'e geri dönmek. Benim durumumda ben kullanıldığı vermedi iconv
gibi$output = iconv("UTF-8//", "ISO-8859-1//IGNORE", $input );
Metin, utf8 olmayan karakter içerebilir . Önce yapmayı deneyin:
$nonutf8 = mb_convert_encoding($nonutf8 , 'UTF-8', 'UTF-8');
Bununla ilgili daha fazla bilgiyi buradan okuyabilirsiniz: http://php.net/manual/en/function.mb-convert-encoding.php news
UConverter PHP 5.5'ten beri kullanılabilir. Intl uzantı kullanıyorsanız ve mbstring kullanmıyorsanız UConverter daha iyi bir seçimdir.
function replace_invalid_byte_sequence($str)
{
return UConverter::transcode($str, 'UTF-8', 'UTF-8');
}
function replace_invalid_byte_sequence2($str)
{
return (new UConverter('UTF-8', 'UTF-8'))->convert($str);
}
htmlspecialchars, PHP 5.4'ten beri geçersiz bayt dizisini kaldırmak için kullanılabilir. Htmlspecialchars, büyük bayt boyutunu ve doğruluğunu işlemek için preg_match'ten daha iyidir. Düzenli ifade kullanılarak yapılan birçok yanlış uygulama görülebilir.
function replace_invalid_byte_sequence3($str)
{
return htmlspecialchars_decode(htmlspecialchars($str, ENT_SUBSTITUTE, 'UTF-8'));
}
Bir dizeden geçersiz UTF-8 karakterlerini silen bir işlev yaptım. XML dışa aktarma dosyasını oluşturmadan önce 27000 ürünün açıklamasını temizlemek için kullanıyorum.
public function stripInvalidXml($value) {
$ret = "";
$current;
if (empty($value)) {
return $ret;
}
$length = strlen($value);
for ($i=0; $i < $length; $i++) {
$current = ord($value{$i});
if (($current == 0x9) || ($current == 0xA) || ($current == 0xD) || (($current >= 0x20) && ($current <= 0xD7FF)) || (($current >= 0xE000) && ($current <= 0xFFFD)) || (($current >= 0x10000) && ($current <= 0x10FFFF))) {
$ret .= chr($current);
}
else {
$ret .= "";
}
}
return $ret;
}
ord()
0-255 aralığındaki sonuçları döndürür. if
Bu işlevdeki dev ord()
, asla dönmeyecek unicode aralıklarını test eder . Bu işlevin neden bu şekilde çalıştığını açıklığa kavuşturmak isteyen varsa, içgörüyü takdir ediyorum.
2019'a hoş geldiniz ve /u
sizin için UTF-8 çok baytlı karakterleri işleyecek normal ifadede değiştirici
Yalnızca kullanırsanız mb_convert_encoding($value, 'UTF-8', 'UTF-8')
, dizenizde yine de yazdırılamayan karakterlerle karşılaşacaksınız.
Bu yöntem:
mb_convert_encoding
\r
, \x00
(NULL-byte) ile diğer denetim karakterpreg_replace
function utf8_filter(string $value): string{
return preg_replace('/[^[:print:]\n]/u', '', mb_convert_encoding($value, 'UTF-8', 'UTF-8'));
}
[:print:]
tüm yazdırılabilir karakterleri ve \n
satırsonlarını eşleştirin ve diğer her şeyi çıkarın
Aşağıdaki ASCII tablosunu görebilirsiniz .. Yazdırılabilir karakterler 32 ila 127 arasındadır, ancak satırsonu \n
, 0 ila 31 arasında değişen kontrol karakterlerinin bir parçasıdır, bu nedenle normal ifadeye yeni satır eklememiz gerekir./[^[:print:]\n]/u
\x7F
(DEL), \x1B
(Esc) vb. Gibi yazdırılabilir aralığın dışındaki karakterlere sahip dizeleri normal ifade aracılığıyla göndermeyi deneyebilir ve bunların nasıl çıkarıldığını görebilirsiniz.
function utf8_filter(string $value): string{
return preg_replace('/[^[:print:]\n]/u', '', mb_convert_encoding($value, 'UTF-8', 'UTF-8'));
}
$arr = [
'Danish chars' => 'Hello from Denmark with æøå',
'Non-printable chars' => "\x7FHello with invalid chars\r \x00"
];
foreach($arr as $k => $v){
echo "$k:\n---------\n";
$len = strlen($v);
echo "$v\n(".$len.")\n";
$strip = utf8_decode(utf8_filter(utf8_encode($v)));
$strip_len = strlen($strip);
echo $strip."\n(".$strip_len.")\n\n";
echo "Chars removed: ".($len - $strip_len)."\n\n\n";
}
php-mbstring
Varsayılan olarak php'de paketlenmeyen 2047'ye hoş geldiniz .
En son yamadan Drupal'ın Feeds JSON ayrıştırıcı modülüne:
//remove everything except valid letters (from any language)
$raw = preg_replace('/(?:\\\\u[\pL\p{Zs}])+/', '', $raw);
Eğer endişeliyseniz, evet, boşlukları geçerli karakterler olarak tutar.
İhtiyacım olanı yaptım. MySQL'in 'utf8' karakter setine uymayan ve bana "SQLSTATE [HY000]: Genel hata: 1366 Yanlış dize değeri" gibi hatalar veren günümüzde yaygın olan emoji karakterlerini kaldırıyor.
Ayrıntılar için bkz. Https://www.drupal.org/node/1824506#comment-6881382
iconv
Dayalı eski moda regexp daha iyidir preg_replace
günümüzde artık kullanılmamaktadır wich.
ereg_replace()
, özür dilerim.
Belki en kesin çözüm değil, ancak işi tek bir kod satırıyla hallediyor:
echo str_replace("?","",(utf8_decode($str)));
utf8_decode
karakterleri soru işaretine dönüştürür;
str_replace
soru işaretlerini kaldıracaktır.
Dolayısıyla kurallar, ilk UTF-8 sekizlisinin işaretçi olarak yüksek bit setine sahip olması ve daha sonra kaç ek oktlet olduğunu belirtmek için 1 ila 4 bit olmasıdır; daha sonra her ilave oktlet 10'a ayarlanmış yüksek iki bit'e sahip olmalıdır.
Sözde piton şöyle olacaktır:
newstring = ''
cont = 0
for each ch in string:
if cont:
if (ch >> 6) != 2: # high 2 bits are 10
# do whatever, e.g. skip it, or skip whole point, or?
else:
# acceptable continuation of multi-octlet char
newstring += ch
cont -= 1
else:
if (ch >> 7): # high bit set?
c = (ch << 1) # strip the high bit marker
while (c & 1): # while the high bit indicates another octlet
c <<= 1
cont += 1
if cont > 4:
# more than 4 octels not allowed; cope with error
if !cont:
# illegal, do something sensible
newstring += ch # or whatever
if cont:
# last utf-8 was not terminated, cope
Aynı mantık php'ye çevrilebilir olmalıdır. Bununla birlikte, hatalı biçimlendirilmiş bir karakter elde ettiğinizde ne tür bir sıyırma yapılacağı açık değildir.
c = (ch << 1)
(c & 1)
Döngüyü atlayarak ilk seferde sıfır yapacak . Test muhtemelen şöyle olmalı(c & 128)
Unicode temel dil düzleminin dışındaki tüm Unicode karakterlerini kaldırmak için:
$str = preg_replace("/[^\\x00-\\xFFFF]/", "", $str);
Sorudan biraz farklı, ancak yaptığım şey HtmlEncode (string) kullanmak,
burada sözde kod
var encoded = HtmlEncode(string);
encoded = Regex.Replace(encoded, "&#\d+?;", "");
var result = HtmlDecode(encoded);
giriş ve çıkış
"Headlight\x007E Bracket, { Cafe Racer<> Style, Stainless Steel 中文呢?"
"Headlight~ Bracket, { Cafe Racer<> Style, Stainless Steel 中文呢?"
Mükemmel olmadığını biliyorum ama benim için iş yapıyor.
static $preg = <<<'END'
%(
[\x09\x0A\x0D\x20-\x7E]
| [\xC2-\xDF][\x80-\xBF]
| \xE0[\xA0-\xBF][\x80-\xBF]
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}
| \xED[\x80-\x9F][\x80-\xBF]
| \xF0[\x90-\xBF][\x80-\xBF]{2}
| [\xF1-\xF3][\x80-\xBF]{3}
| \xF4[\x80-\x8F][\x80-\xBF]{2}
)%xs
END;
if (preg_match_all($preg, $string, $match)) {
$string = implode('', $match[0]);
} else {
$string = '';
}
bizim hizmetimizde çalışıyor
İconv nasıl olur?
http://php.net/manual/en/function.iconv.php
PHP'nin içinde kullanmadım ama komut satırında benim için her zaman iyi performans gösterdi. Geçersiz karakterlerin yerine geçmesini sağlayabilirsiniz.