簡體   English   中英

如何刪除字符串中的所有不可打印字符?

[英]How to remove all non printable characters in a string?

我想我需要刪除字符 0-31 和 127。

是否有一個函數或一段代碼可以有效地做到這一點?

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修飾符的情況下工作。 但是如果你想刪除其他字符,它會讓生活更輕松......

如果您正在處理 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 具有邊緣優勢。

我認為這是一個有趣的結果,所以把它包括在這里。 重要的不是取這個結果並用它來決定使用哪種方法,而是根據你自己的數據進行基准測試,然后再決定。

這里的許多其他答案都沒有考慮 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

從 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 會去掉換行符和回車符,對於 textarea 來說,它們是完全有效的字符......所以我想,某些正則表達式的答案有時仍然是必要的,例如在查看此內容后線程,我計划為 textareas 執行此操作:

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

這似乎比按數字范圍剝離的許多正則表達式更具可讀性。

你可以使用字符類

/[[:cntrl:]]+/

這更簡單:

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

所有的解決方案都部分起作用,甚至下面的解決方案也可能沒有涵蓋所有情況。 我的問題是嘗試將字符串插入 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;
}

進一步加劇問題的是表格與服務器、連接與內容的呈現,正如這里討論的

我的 UTF-8 兼容版本:

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

您可以使用正則表達式刪除除您希望保留的那些字符之外的所有內容:

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

替換所有不是 (^) 字母 AZ 或 az、數字 0-9、空格、下划線、連字符、加號和與號的所有內容 - 不進行任何操作(即刪除它)。

從輸入字符串中去除所有非 ASCII 字符

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

該代碼刪除了十六進制范圍 0-31 和 128-255 中的任何字符,只留下了結果字符串中的十六進制字符 32-127,在本例中我將其稱為 $result。

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

這將刪除所有控制字符( http://uk.php.net/manual/en/regexp.reference.unicode.php ),留下\\n換行符。 根據我的經驗,控制字符是最常導致打印問題的字符。

@PaulDixon答案 完全錯誤的,因為它 刪除了可打印的 擴展 ASCII 字符128-255! 已部分修正。 我不知道為什么他仍然想從 127 個字符的 7 位 ASCII 集中刪除 128-255,因為它沒有擴展的 ASCII 字符。

但最后重要的是不要刪除 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,因為兩者共享相同的控制集 range

不使用正則表達式的 最快的 ¹ 替代方案:

$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 測試並由我本人驗證。

怎么樣:

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

讓我完全控制我想要包含的內容

標記的 anwser 是完美的,但它錯過了字符 127(DEL),這也是一個不可打印的字符

我的答案是

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

“cedivad”通過瑞典字符 ÅÄÖ 的持續結果為我解決了這個問題。

$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));
    }
?>

對於 Unicode: 0x1d (with 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 刪除除換行符以外的所有不可見字符

這對我有用。 我不得不將任意一種隨機標題的字符串轉換為SEO的slug。

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;

}

我使用https://github.com/neitanod/forceutf8解決了 UTF8 的問題

use ForceUTF8\Encoding;

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

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

\\xFF 刪除 ASCII 之外的字符范圍

很好的答案,你可以在這里找到在這里輸入鏈接描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM