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

Мне кажется, мне нужно удалить символы 0-31 и 127,

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

Ответ 1

7 бит ASCII?

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

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

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

8 бит расширенного ASCII?

Ты упал в машину времени с горячей водой, и ты вернулся в восьмидесятых. Если у вас есть форма 8-битного ASCII, вы можете сохранить символы в диапазоне 128-255. Легкая настройка - просто найдите 0-31 и 127

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

UTF-8?

А, добро пожаловать в 21-й век. Если у вас есть кодированная строка UTF-8, то в regex

можно использовать /u modifier,
$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $string);

Это просто удаляет 0-31 и 127. Это работает в ASCII и UTF-8, потому что оба разделяют тот же диапазон набора настроек (как отмечено по мгутт ниже). Строго говоря, это будет работать без модификатора /u. Но это облегчает жизнь, если вы хотите удалить другие символы...

Если вы имеете дело с Unicode, есть потенциально много непечатаемых элементов, но рассмотрим простой: NO-BREAK SPACE (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 символов, я всегда видел preg_replace. В диапазоне 1-8kb у str_replace был крайний край.

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

Ответ 2

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

$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

Ответ 3

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

/[[:cntrl:]]+/

Ответ 4

Начиная с PHP 5.2, у нас также есть доступ к filter_var, который я не видел упоминания о том, что я бы выбрал его там. Чтобы использовать filter_var для удаления непечатаемых символов < 32 и > 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 будет лишать строки новой строки и каретки, которые для текстового поля являются полностью допустимыми символами... поэтому некоторые из ответов Regex, по-моему, по-прежнему необходимы порой, например. после просмотра этой темы я планирую сделать это для текстовых областей:

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

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

Ответ 5

это проще:

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

Ответ 6

Все решения работают частично и даже ниже, вероятно, не охватывают все случаи. Моя проблема заключалась в попытке вставить строку в таблицу 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;
}

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

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

Ответ 10

Ответ @PaulDixon полностью неправильный, потому что он удаляет печатный расширенные символы ASCII 128-255! был частично исправлен. Я не знаю, почему он все еще хочет удалить 128-255 из 7-битного набора ASCII из 127 символов, поскольку он не имеет расширенных символов 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, потому что оба разделяют тот же диапазон набора настроек.

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

$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 и проверено мной.

Ответ 11

как насчет:

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

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

Ответ 12

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

мой ответ был бы

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

Ответ 13

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

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

Спасибо!

Ответ 14

Это сработало для меня. Я должен был преобразовать строку любого типа, которая была случайным заголовком для пули для 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;

}