PHP : 문자열에서 인쇄 할 수없는 모든 문자를 제거하는 방법?


161

0-31과 127 문자를 제거해야한다고 생각합니다.

이 작업을 효율적으로 수행하는 기능이나 코드가 있습니까?

답변:


355

7 비트 ASCII?

Tardis가 1963 년에 출시되었고 7 비트 인쇄 가능한 ASCII 문자를 원한다면 다음과 같이 0-31 및 127-255의 모든 항목을 제거 할 수 있습니다.

$string = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $string);

0-31, 127-255 범위의 모든 항목과 일치하고 제거합니다.

8 비트 확장 ASCII?

당신은 핫 터브 타임머신에 빠졌고 80 년대로 돌아 왔습니다. 8 비트 ASCII 형식이있는 경우 문자를 128-255 범위로 유지하는 것이 좋습니다. 쉬운 조정-0-31 및 127 만 찾으십시오.

$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);

UTF-8?

아, 21 세기로 다시 오신 걸 환영합니다. UTF-8로 인코딩 된 문자열이있는 경우 정규식 에서 /u 수정자를 사용할 수 있습니다.

$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $string);

이것은 0-31과 127 만 제거합니다. ASCII와 UTF-8에서 모두 작동 합니다 (아래의 mgutt에서 언급 한 것처럼). 엄밀히 말하면 이것은 /u수정 자 없이 작동합니다 . 그러나 다른 문자를 제거하려면 인생을 더 쉽게 만듭니다 ...

유니 코드를 다루는 경우 비 인쇄 요소가 많을 수 있지만 간단한 요소를 고려하십시오 .NO-BREAK SPACE (U + 00A0)

UTF-8 문자열에서 이것은로 인코딩됩니다 0xC2A0. 특정 시퀀스를 찾아서 제거 할 수 있지만 /u수정자가 있으면 \xA0문자 클래스에 간단히 추가 할 수 있습니다 .

$string = preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $string);

부록 : str_replace는 어떻습니까?

preg_replace는 매우 효율적이지만이 작업을 많이 수행하는 경우 제거하려는 문자 배열을 작성하고 아래의 mgutt로 표시된 str_replace를 사용할 수 있습니다.

//build an array we can re-use across several operations
$badchar=array(
    // control characters
    chr(0), chr(1), chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8), chr(9), chr(10),
    chr(11), chr(12), chr(13), chr(14), chr(15), chr(16), chr(17), chr(18), chr(19), chr(20),
    chr(21), chr(22), chr(23), chr(24), chr(25), chr(26), chr(27), chr(28), chr(29), chr(30),
    chr(31),
    // non-printing characters
    chr(127)
);

//replace the unwanted chars
$str2 = str_replace($badchar, '', $str);

직관적으로, 이것은 빠른 것처럼 보이지만 항상 그런 것은 아닙니다. 당신이 무엇을 절약하는지 확실히 벤치마킹해야합니다. 임의의 데이터로 다양한 문자열 길이에서 벤치 마크를 했으며이 패턴은 PHP 7.0.12를 사용하여 나타났습니다.

     2 chars str_replace     5.3439ms preg_replace     2.9919ms preg_replace is 44.01% faster
     4 chars str_replace     6.0701ms preg_replace     1.4119ms preg_replace is 76.74% faster
     8 chars str_replace     5.8119ms preg_replace     2.0721ms preg_replace is 64.35% faster
    16 chars str_replace     6.0401ms preg_replace     2.1980ms preg_replace is 63.61% faster
    32 chars str_replace     6.0320ms preg_replace     2.6770ms preg_replace is 55.62% faster
    64 chars str_replace     7.4198ms preg_replace     4.4160ms preg_replace is 40.48% faster
   128 chars str_replace    12.7239ms preg_replace     7.5412ms preg_replace is 40.73% faster
   256 chars str_replace    19.8820ms preg_replace    17.1330ms preg_replace is 13.83% faster
   512 chars str_replace    34.3399ms preg_replace    34.0221ms preg_replace is  0.93% faster
  1024 chars str_replace    57.1141ms preg_replace    67.0300ms str_replace  is 14.79% faster
  2048 chars str_replace    94.7111ms preg_replace   123.3189ms str_replace  is 23.20% faster
  4096 chars str_replace   227.7029ms preg_replace   258.3771ms str_replace  is 11.87% faster
  8192 chars str_replace   506.3410ms preg_replace   555.6269ms str_replace  is  8.87% faster
 16384 chars str_replace  1116.8811ms preg_replace  1098.0589ms preg_replace is  1.69% faster
 32768 chars str_replace  2299.3128ms preg_replace  2222.8632ms preg_replace is  3.32% faster

타이밍 자체는 10000 회 반복이지만 더 흥미로운 것은 상대적인 차이입니다. 최대 512 자까지, 나는 preg_replace가 항상 승리하는 것을 보았습니다. 1-8kb 범위에서 str_replace는 한계가 있습니다.

나는 그것이 흥미로운 결과라고 생각했기 때문에 여기에 포함시켰다. 중요한 것은이 결과를 가져 와서 사용할 방법을 결정하는 데 사용하는 것이 아니라 자신의 데이터와 벤치 마크 한 다음 결정하는 것입니다.


14
줄 바꿈 안전을 고려해야하는 경우 표현식을 다음과 같이 변경하십시오 (반복적으로 검색 가능). preg_replace (/ [^ \ x0A \ x20- \ x7E] /, '', $ string);
Nick

12
@Dalin“UTF-8 문자”는 없습니다. 유니 코드 기호 / 문자가 있으며 UTF-8은 모든 문자를 나타낼 수있는 인코딩입니다. ASCII 문자 집합 이외의 문자에는이 기능이 작동하지 않습니다.
Mathias Bynens

3
\ xFF 이상의 유니 코드 문자와 일치해야하는 경우 \ x {####}를 사용하십시오
Peter Olson

인쇄 할 수없는 캐릭터 인 \ x7F (127)를 놓쳤습니다
Mubashar

이것은 아랍어 문자, 나쁜 해결책을 제거합니다.
Ayman Hussein

141

여기에있는 다른 많은 답변들은 유니 코드 문자를 고려하지 않습니다 (예 : öäüßйȝîûηы மம ᚉ ⠛). 이 경우 다음을 사용할 수 있습니다.

$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);

\x80-\x9F기술적으로 제어되는 문자 범위 (7 비트 ASCII 문자 범위보다 약간 높음)에 이상한 문자 클래스가 있지만 시간이 지남에 따라 인쇄 가능한 문자에 잘못 사용되었습니다. 이것에 아무런 문제가 없다면 다음을 사용할 수 있습니다.

$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $string);

줄 바꿈, 캐리지 리턴, 탭, 줄 바꿈하지 않는 공백 및 소프트 하이픈도 제거하려면 다음을 사용할 수 있습니다.

$string = preg_replace('/[\x00-\x1F\x7F-\xA0\xAD]/u', '', $string);

당신이 참고 해야한다 위의 예제에 대한 작은 따옴표를 사용합니다.

인쇄 가능한 기본 ASCII 문자를 제외한 모든 것을 제거하려면 (위의 모든 예제 문자가 제거됩니다) 다음을 사용할 수 있습니다.

$string = preg_replace( '/[^[:print:]]/', '',$string);

참조는 http://www.fileformat.info/info/charset/UTF-8/list.htm을 참조하십시오 .


1
정규 표현식은 UTF8 문자를 잘 처리합니다. 그러나 비 UTF8 "특수"문자를 제거합니다. ç, ü 및 ö. '/[\x00-\x1F\x80-\xC0]/u'그대로 두십시오. 나누기 (F7) 및 곱셈 (D7) 부호도 있습니다.
Hazar

@Hazar 예, 올바른 \ x80- \ xFF가 너무 많이 제거되었지만 \ x80- \ xC0은 여전히 ​​너무 제한적입니다. © £ ±와 같은 다른 인쇄 가능한 문자가 누락됩니다. 참조를 위해 utf8-chartable.de
Dalin

1
PHP는 php.net/manual/en/…과 같은 문자 순서를 확장 하므로 @TimMalone 이므로 정규 표현식은 사용자가 말하려는 범위를 볼 수 없습니다.
Dalin

1
7F는 어떻습니까? 그것은해야하지 \x7F-\x9F?
Bell

1
방금 많이 시도해 보았습니다 .regex에서 mb_, htmlspecialchars 등 PHP에서 사용할 수있는 모든 인코딩 기능을 시도했습니다. 작업에 투자 해 주셔서 감사합니다.
John

29

PHP 5.2부터 우리는 filter_var에 액세스 할 수 있습니다. filter_var를 사용하여 인쇄 할 수없는 문자 <32 및> 127을 제거하려면 다음을 수행하십시오.

32 미만의 ASCII 문자 필터링

$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW);

127보다 큰 ASCII 문자 필터링

$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_HIGH);

둘 다 제거 :

$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH);

높은 문자를 제거하면서 낮은 문자 (줄 바꾸기, 탭 등)를 html로 인코딩 할 수도 있습니다.

$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_LOW|FILTER_FLAG_STRIP_HIGH);

HTML 제거, 전자 메일 및 URL 삭제 등의 옵션도 있습니다. 따라서 삭제 (데이터 제거) 및 유효성 검사 (자동 제거 대신 유효하지 않은 경우 false 반환) 옵션이 많이 있습니다.

위생 : http://php.net/manual/en/filter.filters.sanitize.php

유효성 검사 : http://php.net/manual/en/filter.filters.validate.php

그러나 FILTER_FLAG_STRIP_LOW는 줄 바꿈과 캐리지 리턴을 제거하여 텍스트 영역의 경우 완전히 유효한 문자를 제거한다는 문제가 여전히 있습니다. 따라서 정규 표현식 답변 중 일부는 때때로 검토해야합니다. 스레드, 나는 텍스트 영역에 대해 이것을 할 계획이다 :

$string = preg_replace( '/[^[:print:]\r\n]/', '',$input);

이것은 숫자 범위로 제거 된 많은 정규 표현식보다 더 읽기 쉽습니다.



18

이것은 더 간단합니다.

$ string = preg_replace ( '/ [^ [: cntrl :]] /', '', $ string);


5
또한 줄 바꿈, 캐리지 리턴 및 UTF8 문자를 제거합니다.
Dalin

5
@Dalin“UTF-8 문자”는 없습니다. 유니 코드 기호 / 문자가 있으며 UTF-8은 모든 문자를 나타낼 수있는 인코딩입니다. ASCII 범위벗어난 문자도 제거 합니다 .
Mathias Bynens

1
아랍어를 먹습니다 :)
Rolf

16

모든 솔루션이 부분적으로 작동하며 아래의 경우에도 모든 경우를 다루지는 않습니다. 내 문제는 utf8 mysql 테이블에 문자열을 삽입하려고했습니다. 문자열 (및 그 바이트)은 모두 utf8을 준수하지만 몇 가지 잘못된 시퀀스가 ​​있습니다. 나는 그들 중 대부분이 제어 또는 형식이라고 가정합니다.

function clean_string($string) {
  $s = trim($string);
  $s = iconv("UTF-8", "UTF-8//IGNORE", $s); // drop all non utf-8 characters

  // this is some bad utf-8 byte sequence that makes mysql complain - control and formatting i think
  $s = preg_replace('/(?>[\x00-\x1F]|\xC2[\x80-\x9F]|\xE2[\x80-\x8F]{2}|\xE2\x80[\xA4-\xA8]|\xE2\x81[\x9F-\xAF])/', ' ', $s);

  $s = preg_replace('/\s+/', ' ', $s); // reduce all multiple whitespace to a single space

  return $s;
}

로 더 악화에 문제는 콘텐츠의 렌더링 대 표 대 서버 대 연결이며, 여기에 약간의 이야기


1
모든 단위 테스트를 통과 한 유일한 제품입니다.
Korri

\ xE2 \ x80 [\ xA4- \ xA8] (또는 226.128. [164-168])-잘못된 인쇄 순서는 다음 인쇄 가능한 기호를 포함합니다 : Unicode 문자 'ONE DOT LEADER'(U + 2024), Unicode 문자 'TWO DOT LEADER '(U + 2025), 유니 코드 문자'HORIZONTAL ELLIPSIS '(U + 2026), 유니 코드 문자'HYPHENATION POINT '(U + 2027) 그리고 인쇄 할 수없는 단 하나의 유니 코드 문자 'LINE SEPARATOR'(U + 2028). 다음은 인쇄 할 수 없습니다 : 유니 코드 문자 'PARAGRAPH SEPARATOR'(U + 2029). 따라서 시퀀스를 \ xE2 \ x80 [\ xA8- \ xA9] \ xE2 \ x80 [\ xA8- \ xA9]로 바꾸어 LINE SEPARATOR 및 PARAGRAPH SEPARATOR를 제거하십시오.
MingalevME

이것은 내가 지금까지 찾을 수있는,하지만 난 LASO 추가했다 최적의 솔루션입니다 $s = preg_replace('/(\xF0\x9F[\x00-\xFF][\x00-\xFF])/', ' ', $s);때문에 모든 이모티콘 문자의 것은 MySQL의를 엉망으로했다
조 블랙

9

내 UTF-8 호환 버전 :

preg_replace('/[^\p{L}\s]/u','',$value);


7
이것은 따옴표, 괄호 등의 문자를 잘 제거합니다. 확실히 인쇄 가능한 문자입니다.
Gajus

이것은 훌륭하다! 그것은 내 생명을 구하고 아랍어 문자를 인쇄하는 동안 엉망으로 챔프처럼 일했습니다 :)
krishna

6

정규 표현을 사용하여 유지하려는 문자와 다른 모든 것을 제거 할 수 있습니다.

$string=preg_replace('/[^A-Za-z0-9 _\-\+\&]/','',$string);

문자 AZ 또는 az (0), 숫자 0-9, 공백, 밑줄, 하이픈 및 앰퍼샌드 (^)가 아닌 모든 것을 대체합니다 (즉, 제거).


5
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);

이것은 개행 문자를 남기는 모든 제어 문자 ( http://uk.php.net/manual/en/regexp.reference.unicode.php )를 제거합니다 \n. 내 경험상 컨트롤 문자는 인쇄 문제를 가장 자주 일으키는 문자입니다.


1
그것은 나를 위해 완벽하게 작동합니다! /uUTF-8 문자 에만 추가했습니다 . 첫 번째 부분 (?!\n)이 무엇인지 설명해 주 시겠습니까?
Marcio Mazzucato

4

입력 문자열에서 모든 비 ASCII 문자를 제거하려면

$result = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $string);

이 코드는 16 진수 범위 0-31 및 128-255의 문자를 제거하고 결과 문자열에는 16 진수 문자 32-127 만 남겨두고이 예제에서는 $ result라고합니다.


3

@PaulDixon의 대답은 이다 완전히 잘못 이 있기 때문에, 인쇄 제거 확장 ASCII 문자 128-255을! 부분적으로 수정되었습니다. 확장 ASCII 문자가 없기 때문에 왜 여전히 127 자 7 비트 ASCII 세트에서 128-255를 삭제하려고하는지 모르겠습니다.

그러나 마지막으로 128-255를 삭제하지 않는 것이 중요했습니다. 예를 들어 chr(128)( \x80)는 8 비트 ASCII 의 유로 기호 이고 Windows의 많은 UTF-8 글꼴은 자체 테스트와 관련 하여 유로 기호 와 Android를 표시합니다 .

UTF-8 문자열 (아마도 멀티 바이트 UTF-8 문자의 시작 바이트)에서 ASCII 문자 128-255를 제거하면 많은 UTF-8 문자가 종료됩니다. 그러지 마! 현재 사용되는 모든 파일 시스템에서 완전히 유효한 문자입니다. 유일하게 예약 된 범위는 0-31 입니다.

대신 이것을 사용하여 인쇄 할 수없는 문자 0-31 및 127을 삭제하십시오.

$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);

그것은 ASCII와 UTF-8에서 작동 모두 공유하기 때문에 동일한 제어 설정 범위 .

빠른 정규 표현식을 사용하지 않고 slower¹ 대안 :

$string = str_replace(array(
    // control characters
    chr(0), chr(1), chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8), chr(9), chr(10),
    chr(11), chr(12), chr(13), chr(14), chr(15), chr(16), chr(17), chr(18), chr(19), chr(20),
    chr(21), chr(22), chr(23), chr(24), chr(25), chr(26), chr(27), chr(28), chr(29), chr(30),
    chr(31),
    // non-printing characters
    chr(127)
), '', $string);

모든 공백 문자를 유지하려면 \t, \n그리고 \r, 다음 제거 chr(9), chr(10)그리고 chr(13)이 목록에서. 참고 : 일반적인 공백은 chr(32)결과에 그대로 유지됩니다. 중단되지 않는 공간을 제거하려면 chr(160)문제를 일으킬 수 있으므로 스스로 결정하십시오 .

¹ @PaulDixon에서 테스트하고 직접 확인했습니다.


2

어때요?

return preg_replace("/[^a-zA-Z0-9`_.,;@#%~'\"\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:\-\s\\\\]+/", "", $data);

내가 포함하고 싶은 것을 완벽하게 제어합니다.


0

표시된 답변은 완벽하지만 인쇄 할 수없는 문자 인 127 (DEL) 문자가 누락되었습니다

내 대답은

$string = preg_replace('/[\x00-\x1F\x7f-\xFF]/', '', $string);

이 답변도 잘못되었습니다. 참조 : stackoverflow.com/a/42058165/318765
mgutt

위의 답변은 "삭제"문자 만 추가하는 원래 답변에 대한 칭찬이었습니다.
Mubashar

0

"cedivad"는 스웨덴 문자 ÅÄÖ의 지속적인 결과로이 문제를 해결했습니다.

$text = preg_replace( '/[^\p{L}\s]/u', '', $text );

감사!


0

인쇄 할 수없는 문자를 제거하지 않고 이스케이프 처리하지 않고이 작업을 수행하는 방법을 계속 찾고있는 사람이라면 도움이 될 것입니다. 자유롭게 개선하십시오! 문자는 \\ x [A-F0-9] [A-F0-9]로 이스케이프됩니다.

이렇게 전화하십시오 :

$escaped = EscapeNonASCII($string);

$unescaped = UnescapeNonASCII($string);

<?php 
  function EscapeNonASCII($string) //Convert string to hex, replace non-printable chars with escaped hex
    {
        $hexbytes = strtoupper(bin2hex($string));
        $i = 0;
        while ($i < strlen($hexbytes))
        {
            $hexpair = substr($hexbytes, $i, 2);
            $decimal = hexdec($hexpair);
            if ($decimal < 32 || $decimal > 126)
            {
                $top = substr($hexbytes, 0, $i);
                $escaped = EscapeHex($hexpair);
                $bottom = substr($hexbytes, $i + 2);
                $hexbytes = $top . $escaped . $bottom;
                $i += 8;
            }
            $i += 2;
        }
        $string = hex2bin($hexbytes);
        return $string;
    }
    function EscapeHex($string) //Helper function for EscapeNonASCII()
    {
        $x = "5C5C78"; //\x
        $topnibble = bin2hex($string[0]); //Convert top nibble to hex
        $bottomnibble = bin2hex($string[1]); //Convert bottom nibble to hex
        $escaped = $x . $topnibble . $bottomnibble; //Concatenate escape sequence "\x" with top and bottom nibble
        return $escaped;
    }

    function UnescapeNonASCII($string) //Convert string to hex, replace escaped hex with actual hex.
    {
        $stringtohex = bin2hex($string);
        $stringtohex = preg_replace_callback('/5c5c78([a-fA-F0-9]{4})/', function ($m) { 
            return hex2bin($m[1]);
        }, $stringtohex);
        return hex2bin(strtoupper($stringtohex));
    }
?>

0

https://github.com/neitanod/forceutf8을 사용하여 UTF8의 문제를 해결했습니다.

use ForceUTF8\Encoding;

$string = Encoding::fixUTF8($string);

1
이 lib는 UTF-8 악센트 ​​문자 및 UTF-8 이모티콘을 "?"로 변환합니다. 기호. 불행히도 상당히 심각한 문제입니다.
ChristoKiwi

0

선택한 답변에 대한 정규식이 유니 코드에 대해 실패합니다 : 0x1d (php 7.4 포함)

해결책 :

<?php
        $ct = 'différents'."\r\n test";

        // fail for Unicode: 0x1d
        $ct = preg_replace('/[\x00-\x1F\x7F]$/u', '',$ct);

        // work for Unicode: 0x1d
        $ct =  preg_replace( '/[^\P{C}]+/u', "",  $ct);

        // work for Unicode: 0x1d and allow line break
        $ct =  preg_replace( '/[^\P{C}\n]+/u', "",  $ct);

        echo $ct;

from : UTF 8 String 개행을 제외한 모든 보이지 않는 문자 제거

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.