문자열에서 UTF8이 아닌 문자 제거
제대로 표시되지 않는 문자열에서 UTF8이 아닌 문자를 제거하는 데 문제가 있습니다. 문자는 다음과 같습니다. 0x97 0x61 0x6C 0x6F (16 진수 표현)
제거하는 가장 좋은 방법은 무엇입니까? 정규 표현식이나 다른 것?
정규식 접근 방식 사용 :
$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 문자 시퀀스와 일치시킵니다.
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
다운로드 :
https://github.com/neitanod/forceutf8
mbstring을 사용할 수 있습니다.
$text = mb_convert_encoding($text, 'UTF-8', 'UTF-8');
... 유효하지 않은 문자를 제거합니다.
참조 : 유효하지 않은 UTF-8 문자를 물음표로 대체하면 mbstring.substitute_character가 무시 된 것 같습니다.
이 함수는 모든 비 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?
$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
플래그를 추가 하면 함수는 출력 문자 집합 으로 표시 할 수없는 입력 문자열의 모든 문자를 삭제 (스트립)합니다. 따라서 실제로 입력 문자열을 필터링합니다.
텍스트에는 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 can be used to remove invalid byte sequence since PHP 5.4. Htmlspecialchars is better than preg_match for handling large size of byte and the accuracy. A lot of the wrong implementation by using regular expression can be seen.
function replace_invalid_byte_sequence3($str)
{
return htmlspecialchars_decode(htmlspecialchars($str, ENT_SUBSTITUTE, 'UTF-8'));
}
I have made a function that deletes invalid UTF-8 characters from a string. I'm using it to clear description of 27000 products before it generates the XML export file.
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;
}
$string = preg_replace('~&([a-z]{1,2})(acute|cedil|circ|grave|lig|orn|ring|slash|th|tilde|uml);~i', '$1', htmlentities($string, ENT_COMPAT, 'UTF-8'));
From recent patch to Drupal's Feeds JSON parser module:
//remove everything except valid letters (from any language)
$raw = preg_replace('/(?:\\\\u[\pL\p{Zs}])+/', '', $raw);
If you're concerned yes it retains spaces as valid characters.
Did what I needed. It removes widespread nowadays emoji-characters that don't fit into MySQL's 'utf8' character set and that gave me errors like "SQLSTATE[HY000]: General error: 1366 Incorrect string value".
For details see https://www.drupal.org/node/1824506#comment-6881382
So the rules are that the first UTF-8 octlet has the high bit set as a marker, and then 1 to 4 bits to indicate how many additional octlets; then each of the additional octlets must have the high two bits set to 10.
The pseudo-python would be:
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
This same logic should be translatable to php. However, its not clear what kind of stripping is to be done once you get a malformed character.
To remove all Unicode characters outside of the Unicode basic language plane:
$str = preg_replace("/[^\\x00-\\xFFFF]/", "", $str);
Slightly different to the question, but what I am doing is to use HtmlEncode(string),
pseudo code here
var encoded = HtmlEncode(string);
encoded = Regex.Replace(encoded, "&#\d+?;", "");
var result = HtmlDecode(encoded);
input and output
"Headlight\x007E Bracket, { Cafe Racer<> Style, Stainless Steel 中文呢?"
"Headlight~ Bracket, { Cafe Racer<> Style, Stainless Steel 中文呢?"
I know it's not perfect, but does the job for me.
Welcome to 2019 and the /u
modifier in regex which will handle UTF-8 multibyte chars for you
If you only use mb_convert_encoding($value, 'UTF-8', 'UTF-8')
you will still end up with non-printable chars in your string
This method will:
- Remove all invalid UTF-8 multibyte chars with
mb_convert_encoding
- Remove all non-printable chars like
\r
,\x00
(NULL-byte) and other control chars withpreg_replace
method:
function utf8_filter(string $value): string{
return preg_replace('/[^[:print:]\n]/u', '', mb_convert_encoding($value, 'UTF-8', 'UTF-8'));
}
[:print:]
match all printable chars and \n
newlines and strip everything else
You can see the ASCII table below.. The printable chars range from 32 to 127, but newline \n
is a part of the control chars which range from 0 to 31 so we have to add newline to the regex /[^[:print:]\n]/u
You can try to send strings through the regex with chars outside the printable range like \x7F
(DEL), \x1B
(Esc) etc. and see how they are stripped
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";
}
https://www.tehplayground.com/q5sJ3FOddhv1atpR
How about iconv:
http://php.net/manual/en/function.iconv.php
Haven't used it inside PHP itself but its always performed well for me on the command line. You can get it to substitute invalid characters.
참고URL : https://stackoverflow.com/questions/1401317/remove-non-utf8-characters-from-string
'development' 카테고리의 다른 글
vba에서 문자열에 큰 따옴표를 어떻게 넣습니까? (0) | 2020.08.20 |
---|---|
PostgreSQL에 이미지 저장 (0) | 2020.08.20 |
화면이 나타날 때 필드의 자동 초점 / 키보드 팝업을 제거하는 방법은 무엇입니까? (0) | 2020.08.19 |
url에서 Pandas read_csv (0) | 2020.08.19 |
플롯의 오른쪽에 Python Matplotlib Y 축 눈금 (0) | 2020.08.19 |