PHP: Как удалить все непечатаемые символы в строке?
Я думаю, мне нужно удалить символы 0-31 и 127,
Есть ли функция или кусок кода, чтобы сделать это эффективно.
20 ответов
7 бит ASCII?
Если ваш Tardis только что приземлился в 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, то /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 довольно эффективен, но если вы много делаете эту операцию, вы можете создать массив символов, которые вы хотите удалить, и использовать 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 win. В диапазоне 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
Начиная с 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, я думаю, иногда все же необходимы, например, после просмотра этого я планирую сделать это для textareas:
$string = preg_replace( '/[^[:print:]\r\n]/', '',$input);
Это кажется более читабельным, чем число регулярных выражений, которые были удалены по числовому диапазону.
Все решения работают частично, и даже ниже, вероятно, не охватывает все случаи. Моя проблема заключалась в попытке вставить строку в таблицу mysql utf8. Строка (и ее байты) все соответствовали 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;
}
Чтобы еще больше усугубить проблему, это таблица "сервер против сервера", "соединение" и "рендеринг контента", о чем немного говорилось здесь.
Это проще:
$ string = preg_replace ('/ [^ [: cntrl:]] /', '', $ string);
Для удаления всех не-ASCII символов из входной строки
$result = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $string);
Этот код удаляет любые символы в шестнадцатеричных диапазонах 0-31 и 128-255, оставляя только шестнадцатеричные символы 32-127 в результирующей строке, которую я называю $result в этом примере.
Моя версия, совместимая с UTF-8:
preg_replace('/[^\p{L}\s]/u','',$value);
Вы можете использовать регулярный экспресс, чтобы удалить все, кроме тех символов, которые вы хотите сохранить:
$string=preg_replace('/[^A-Za-z0-9 _\-\+\&]/','',$string);
Заменяет все, что не является (^) буквами AZ или az, числами 0-9, пробелом, подчеркиванием, гипеном, плюсом и амперсандом - ничем (т.е. удаляет его).
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);
Это удалит все управляющие символы ( http://uk.php.net/manual/en/regexp.reference.unicode.php), оставив \n
символы новой строки. Исходя из моего опыта, именно контрольные символы чаще всего вызывают проблемы с печатью.
Ответ @PaulDixon совершенно неправильный, потому что он удаляет печатаемые расширенные символы ASCII 128-255! был частично исправлен. Я не знаю, почему он все еще хочет удалить 128-255 из 127-битного набора 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 и проверено мной.
Регулярное выражение в выбранном ответе не работает для Unicode: 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 удалить все невидимые символы, кроме новой строки
Как насчет:
return preg_replace("/[^a-zA-Z0-9`_.,;@#%~'\"\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:\-\s\\\\]+/", "", $data);
дает мне полный контроль над тем, что я хочу включить
Для тех, кто все еще ищет, как это сделать, не удаляя непечатаемые символы, а скорее избегая их, я сделал это, чтобы помочь. Не стесняйтесь улучшать это! Символы экранируются в \\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));
}
?>
Помеченный anwser идеален, но ему не хватает символа 127(DEL), который также не может быть напечатан
мой ответ будет
$string = preg_replace('/[\x00-\x1F\x7f-\xFF]/', '', $string);
Интересно, почему об этом никто не упомянул:
- поскольку функции PHP просто предполагают, что каждый байт представляет собой один символ. мы должны использовать аналог.
и если у вас есть пользователи со всего мира, вы должны это учитывать, потому что при использовании PHP просто удаляются символы CJK, арабские и грузинские символы.preg_replace
еще одна проблема, с которой я столкнулся
mb_
требовалось, чтобы шаблон был просто строкой и не был заключен в модификатор запуска/остановки, например/pattern/im
.еще одно примечание: если вы используете
^[:print:]
он просто сохранит все, что между ними0x20-0x7e
поэтому отбросим все символы выше0x800
но если вы используете[:cntrl:]
оно просто упадет0x00 - 0x1f
&0x7f
(Символ «DEL»). так что вы можете легко сохранить все расширенные символы ASCII.
мой рабочий фрагмент кода выглядит следующим образом:
$pattern = "[[:cntrl:]".PHP_EOL."]";
mb_ereg_replace($pattern, '', $text);
"Седивад" решил проблему для меня с постоянным результатом шведских символов ÅÄÖ.
$text = preg_replace( '/[^\p{L}\s]/u', '', $text );
Спасибо!
Я решил проблему для UTF8, используя https://github.com/neitanod/forceutf8
use ForceUTF8\Encoding;
$string = Encoding::fixUTF8($string);
Это сработало для меня. Я должен был преобразовать строку любого вида, которая была случайным названием в слаг для 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;
}
$str = preg_replace('/[\x00-\x1F\xFF]/', "", $ str);
\xFF удалить диапазон символов за пределами ASCII
хороший ответ вы можете найти здесь введите описание ссылки здесь