답변:
정규식 접근 방식 사용 :
$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 시퀀스를 검색하여 그룹 1로 캡처합니다. 또한 UTF-8 시퀀스의 일부로 식별 할 수없는 단일 바이트와 일치하지만 캡처하지는 않습니다. 대체는 그룹 1로 캡처 된 모든 것입니다. 이는 유효하지 않은 모든 바이트를 효과적으로 제거합니다.
유효하지 않은 바이트를 UTF-8 문자로 인코딩하여 문자열을 복구 할 수 있습니다. 그러나 오류가 무작위이면 이상한 기호가 남을 수 있습니다.
$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);
편집하다:
!empty(x)
비어 있지 않은 값과 일치합니다 ( "0"
비어있는 것으로 간주 됨).x != ""
를 포함하여 비어 있지 않은 값과 일치 "0"
합니다.x !== ""
를 제외한 모든 항목과 일치 ""
합니다.x != ""
이 경우에 사용하기에 가장 좋은 것 같습니다.
나는 또한 경기 속도를 약간 높였습니다. 각 문자를 개별적으로 일치시키는 대신 유효한 UTF-8 문자 시퀀스와 일치시킵니다.
$regex = <<<'END'
PHP <5.3.x 대신 무엇을 사용해야 합니까?
elseif (!empty($captures([2])) {
사용해야 !== ""
합니다 "0"
. 또한이 기능은 매우 느립니다. 더 빨리 할 수 있습니까?
utf8_encode()
이미 UTF8 문자열에 적용 하면 잘못된 UTF8 출력이 반환됩니다.
이 모든 문제를 해결하는 기능을 만들었습니다. 라고 Encoding::toUTF8()
합니다.
문자열의 인코딩이 무엇인지 알 필요가 없습니다. Latin1 (ISO8859-1), Windows-1252 또는 UTF8이거나 문자열에 이들을 혼합 할 수 있습니다. Encoding::toUTF8()
모든 것을 UTF8로 변환합니다.
서비스가 데이터 피드를 모두 엉망으로 제공하여 동일한 문자열에서 인코딩을 혼합했기 때문에 그렇게했습니다.
용법:
require_once('Encoding.php');
use \ForceUTF8\Encoding; // It's namespaced now.
$utf8_string = Encoding::toUTF8($mixed_string);
$latin1_string = Encoding::toLatin1($mixed_string);
또 다른 함수 인 Encoding :: fixUTF8 ()을 포함 시켰는데, 이는 UTF8로 여러 번 인코딩 된 왜곡 된 제품으로 보이는 모든 UTF8 문자열을 수정합니다.
용법:
require_once('Encoding.php');
use \ForceUTF8\Encoding; // It's namespaced now.
$utf8_string = Encoding::fixUTF8($garbled_utf8_string);
예 :
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");
다음을 출력합니다.
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
다운로드 :
mbstring을 사용할 수 있습니다.
$text = mb_convert_encoding($text, 'UTF-8', 'UTF-8');
... 유효하지 않은 문자를 제거합니다.
참조 : 유효하지 않은 UTF-8 문자를 물음표로 대체하면 mbstring.substitute_character가 무시 된 것 같습니다.
<0x1a>
<0x1a>
하지 않았다면 인쇄 가능한 문자는 아니지만 완벽하게 유효한 UTF-8 시퀀스입니다. 인쇄 할 수없는 문자에 문제가 있습니까? 이 확인 stackoverflow.com/questions/1176904/...
ini_set('mbstring.substitute_character', 'none');
그렇지 않으면 결과에 물음표가 표시되었습니다.
이 함수는 모든 비 ASCII 문자를 제거합니다. 유용하지만 질문을 해결하지는 못합니다.
이것은 인코딩에 관계없이 항상 작동하는 내 함수입니다.
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;
}
작동 원리 :
echo remove_bs('Hello õhowå åare youÆ?'); // Hello how are you?
í
유효한 UTF-8 문자 인 주소 필드의 문자 였습니다 . 표 참조 . 사기 : API 오류 메시지를 신뢰하지 마십시오 :)
$text = iconv("UTF-8", "UTF-8//IGNORE", $text);
이것이 내가 사용하는 것입니다. 꽤 잘 작동하는 것 같습니다. http://planetozh.com/blog/2005/01/remove-invalid-characters-in-utf-8/ 에서 가져옴
이 시도:
$string = iconv("UTF-8","UTF-8//IGNORE",$string);
iconv manual 에 따르면 이 함수는 첫 번째 매개 변수를 입력 문자 집합으로, 두 번째 매개 변수를 출력 문자 집합으로, 세 번째 매개 변수를 실제 입력 문자열로 사용합니다.
입력 및 출력 문자 집합을 모두 UTF-8로 설정하고 출력 문자 집합 에 //IGNORE
플래그를 추가 하면 함수는 출력 문자 집합 으로 표시 할 수없는 입력 문자열의 모든 문자를 삭제 (스트립)합니다. 따라서 실제로 입력 문자열을 필터링합니다.
iconv
. @halfer 아마도 입력 데이터가 utf-8이 아닐 수 있습니다. 또 다른 옵션은 ascii로 다시 변환 한 다음 다시 utf-8로 다시 변환하는 것입니다. 내 경우에는 내가 사용 않았다 iconv
처럼$output = iconv("UTF-8//", "ISO-8859-1//IGNORE", $input );
텍스트에는 UTF8이 아닌 문자가 포함될 수 있습니다 . 먼저 시도하십시오.
$nonutf8 = mb_convert_encoding($nonutf8 , 'UTF-8', 'UTF-8');
여기에서 자세한 내용을 읽을 수 있습니다. http://php.net/manual/en/function.mb-convert-encoding.php 뉴스
UConverter는 PHP 5.5부터 사용할 수 있습니다. intl 확장자를 사용하고 mbstring을 사용하지 않는 경우 UConverter가 더 나은 선택입니다.
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부터 유효하지 않은 바이트 시퀀스를 제거하는 데 사용할 수 있습니다. Htmlspecialchars는 큰 크기의 바이트와 정확성을 처리하기 위해 preg_match보다 낫습니다. 정규 표현식을 사용하여 잘못된 구현을 많이 볼 수 있습니다.
function replace_invalid_byte_sequence3($str)
{
return htmlspecialchars_decode(htmlspecialchars($str, ENT_SUBSTITUTE, 'UTF-8'));
}
문자열에서 잘못된 UTF-8 문자를 삭제하는 함수를 만들었습니다. XML 내보내기 파일을 생성하기 전에 27000 제품에 대한 설명을 지우는 데 사용하고 있습니다.
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 범위의 결과를 반환합니다. if
이 함수 의 거인 ord()
은 절대 반환되지 않는 유니 코드 범위를 테스트합니다 . 누군가이 기능이 작동하는 이유를 명확히하고 싶다면 통찰력을 고맙게 생각합니다.
2019에 오신 것을 환영합니다. /u
UTF-8 멀티 바이트 문자를 처리 할 정규 표현식 의 수정 자입니다.
사용하는 경우에만 mb_convert_encoding($value, 'UTF-8', 'UTF-8')
문자열에 인쇄 할 수없는 문자가 표시됩니다.
이 방법은 다음을 수행합니다.
mb_convert_encoding
\r
, \x00
(NULL-byte) 및 기타 제어 문자와 같은 인쇄 할 수없는 문자를 모두 제거하십시오.preg_replace
function utf8_filter(string $value): string{
return preg_replace('/[^[:print:]\n]/u', '', mb_convert_encoding($value, 'UTF-8', 'UTF-8'));
}
[:print:]
모든 인쇄 가능한 문자 및 줄 \n
바꿈을 일치시키고 다른 모든 것을 제거하십시오.
아래의 ASCII 테이블을 볼 수 있습니다. 인쇄 가능한 문자는 32에서 127까지 범위이지만 newline \n
은 0에서 31까지 범위의 제어 문자의 일부이므로 정규식에 개행 문자를 추가해야합니다./[^[:print:]\n]/u
\x7F
(DEL), \x1B
(Esc) 등과 같이 인쇄 가능한 범위를 벗어난 문자로 정규식을 통해 문자열을 보내려고 할 수 있습니다 .
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
. 기본적으로는 PHP로 포장되지 않습니다.
최근 패치에서 Drupal의 피드 JSON 파서 모듈까지 :
//remove everything except valid letters (from any language)
$raw = preg_replace('/(?:\\\\u[\pL\p{Zs}])+/', '', $raw);
걱정된다면 공백을 유효한 문자로 유지합니다.
내가 필요한 것을 했어요. MySQL의 'utf8'문자 집합에 맞지 않고 "SQLSTATE [HY000] : 일반 오류 : 1366 잘못된 문자열 값"과 같은 오류를 발생시킨 요즘 널리 퍼져있는 이모 지 문자를 제거합니다.
자세한 내용은 https://www.drupal.org/node/1824506#comment-6881382를 참조 하십시오.
iconv
기반 구식 정규 표현식보다 훨씬 더 나은 preg_replace
현재 사용되지 않습니다 느릅 나무.
ereg_replace()
.
아마도 가장 정확한 솔루션은 아니지만 한 줄의 코드로 작업을 완료합니다.
echo str_replace("?","",(utf8_decode($str)));
utf8_decode
문자를 물음표로 변환합니다.
str_replace
물음표를 제거합니다.
따라서 규칙은 첫 번째 UTF-8 옥 틀릿이 마커로 높은 비트를 설정 한 다음 추가 옥 틀릿 수를 나타내는 1 ~ 4 비트입니다. 그런 다음 각 추가 8 진수는 상위 2 비트를 10으로 설정해야합니다.
의사 파이썬은 다음과 같습니다.
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
이 동일한 논리를 php로 번역 할 수 있어야합니다. 그러나 잘못된 캐릭터가 생기면 어떤 종류의 스트리핑을해야하는지 명확하지 않습니다.
c = (ch << 1)
(c & 1)
루프를 건너 뛰고 처음에는 0이 됩니다 . 테스트는 아마도(c & 128)
질문과 약간 다르지만 내가하는 일은 HtmlEncode (string)을 사용하는 것입니다.
여기에 의사 코드
var encoded = HtmlEncode(string);
encoded = Regex.Replace(encoded, "&#\d+?;", "");
var result = HtmlDecode(encoded);
입력과 출력
"Headlight\x007E Bracket, { Cafe Racer<> Style, Stainless Steel 中文呢?"
"Headlight~ Bracket, { Cafe Racer<> Style, Stainless Steel 中文呢?"
나는 그것이 완벽하지 않다는 것을 알고 있지만 나를 위해 일합니다.
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 = '';
}
그것은 우리의 서비스에서 작동합니다
iconv는 어떻습니까?
http://php.net/manual/en/function.iconv.php
PHP 자체에서 사용하지는 않았지만 항상 명령 줄에서 잘 수행되었습니다. 유효하지 않은 문자로 대체 할 수 있습니다.