PHP: как удалить все непечатаемые символы в строке?

Я полагаю, что мне нужно удалить символы 0-31 и 127,

есть ли функция или часть кода, чтобы сделать это эффективно.

16 ответов


7 бит ASCII?

если ваша Тардис только что приземлилась в 1963 году, и вы просто хотите 7-битные печатные символы ASCII, вы можете вырвать все из 0-31 и 127-255 с помощью этого:

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

он соответствует чему-либо в диапазоне 0-31, 127-255 и удаляет его.

8 бит расширенный ASCII?

$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 модификатор. Но она облегчает жизнь, если вы хотите удалить другие символы...

если вы имеете дело с Unicode, есть потенциально много непечатающих элементов, но давайте рассмотрим простой один: ПРОСТРАНСТВО БЕЗ ПЕРЕРЫВА (U+00A0)

в строке UTF-8 это будет закодировано как 0xC2A0. Вы можете искать и удалять эту конкретную последовательность, но с помощью /u модификатор на месте, вы можете просто добавить \xA0 персонаж класс:

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

добавление: как насчет str_replace?

preg_replace довольно эффективен, но если вы делаете эту операцию много, вы можете создать массив символов, которые хотите удалить, и использовать str_replace, как отмечено mgutt ниже, например

//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 символов, я видел еще всегда выигрывают. В диапазоне 1-8kb str_replace имел маргинальное ребро.

Я думал, что это интересный результат, так это здесь. главное не принять этот результат и использовать его, чтобы решить, какой метод использовать, но для сравнения с ваши собственные данные, а затем решить.


многие другие ответы здесь не учитывают символы юникода (например, öäüßîîûηыეமிᚉ ⠛ ). В этом случае вы можете использовать следующее:

$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


вы можете использовать классы символов

/[[:cntrl:]]+/

начиная с PHP 5.2, у нас также есть доступ к filter_var, о котором я не видел никаких упоминаний, поэтому думал, что выброшу его там. Чтобы использовать filter_var для удаления непечатаемых символов 127, вы можете сделать:

фильтр ASCII символов ниже 32

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

фильтр ASCII символов выше 127

$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 будет удалять новую строку и возврат каретки, которые для textarea являются полностью допустимыми символами...поэтому некоторые ответы регулярных выражений, я думаю, все еще необходимы время от времени, например, после просмотра этого потока, я планирую сделать это для textarea:

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

Это кажется более читаемым, чем ряд регулярных выражений, которые были удалены числовой диапазон.


Это проще:

$строка = код preg_replace( '/[^[: cntrl:]]/',", $string);


все решения работают частично, и даже ниже, вероятно, не охватывают все случаи. Моя проблема заключалась в попытке вставить строку в таблицу mysql utf8. Строка (и ее байты) соответствовала utf8, но имела несколько плохих последовательностей. Я предполагаю, что большинство из них были control или formatting.

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;
}

чтобы еще больше усугубить проблему, это таблица против сервера против соединения против рендеринга контента, как говорили немного здесь


моя версия UTF-8 совместимая:

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


вы можете использовать обычный экспресс, чтобы удалить все, кроме тех символов, которые вы хотите сохранить:

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

заменяет все, что не является ( ^ ) буквами A-Z или a-z, числами 0-9, пробелом, подчеркиванием, гипеном, плюсом и амперсандом - ничем (т. е. удаляет его).


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

это удалит все управляющие символы (http://uk.php.net/manual/en/regexp.reference.unicode.php) покидая \n символы новой строки. По моему опыту, контрольные символы-это те, которые чаще всего вызывают проблемы с печатью.


на ответ @PaulDixon is совершенно неправильно, потому что удаляет для печати расширенные символы ASCII 128-255! частично исправлено. Я не знаю, почему он все еще хочет удалить 128-255 из 127 символов 7-битного набора ASCII, поскольку у него нет расширенных символов ASCII.

но, наконец, было важно не удалять 128-255, потому что, например chr(128) (\x80) является евро войдите в 8-битный ASCII и многие шрифты UTF-8 в Windows отображается знак евро и Android относительно моего собственного теста.

и он убьет много символов UTF-8, Если вы удалите символы ASCII 128-255 из строки UTF-8 (возможно, стартовые байты многобайтового символа UTF-8). Так что не делай этого! Они являются полностью законными символами во всех используемых в настоящее время файловых системах. единственный зарезервированный диапазон 0-31.

вместо того, чтобы использовать это, чтобы удалить непечатаемые символы 0-31 и 127:

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

это работает в ASCII и UTF-8 потому что обе доли тот же диапазон набора управления.

на быстрый альтернатива slower1 без использования регулярных выражений:

$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) как это может вызвать проблемы.

1 проверено @PaulDixon и проверено мной.


Как насчет:

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

дает мне полный контроль над тем, что я хочу включить


отмеченный anwser идеален, но он пропускает символ 127 (DEL), который также является непечатаемым символом

мой ответ будет

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

"cedivad" решил этот вопрос для меня с постоянным результатом шведских chars ÅÄÖ.

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

спасибо!


для тех, кто все еще ищет, как это сделать, не удаляя непечатаемые символы, а скорее избегая их, я сделал это, чтобы помочь. Не стесняйтесь улучшать его! Символы экранируются в \\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));
    }
?>

Я решил проблему для UTF8, используя https://github.com/neitanod/forceutf8

use ForceUTF8\Encoding;

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

это сработало для меня. Мне пришлось преобразовать строку любого типа, которая была случайным заголовком, В slug для SEO.

function string2Slug($str){

    $str = trim($str);
    $str = str_replace(" ","_",$str);
    $temp = explode("\u",$str);
    $str = '';
    foreach ($temp as $bit) {
        $str .= substr($bit,4);
    }

    $str = str_replace("'","",$str);
    $str = str_replace("\"","",$str);
    $str = str_replace("\","",$str);
    $str = str_replace("\/","",$str);
    $str = str_replace("/","",$str);
    $str = str_replace("?","",$str);
    $str = str_replace("#","",$str);
    $str = str_replace("&","",$str);
    $str = str_replace("%","",$str);
    $str = str_replace("!","",$str);

    return $str;

}