ฉันคิดว่าฉันต้องลบตัวอักษร 0-31 และ 127
มีฟังก์ชั่นหรือชิ้นส่วนของรหัสที่จะทำเช่นนี้ได้อย่างมีประสิทธิภาพ
ฉันคิดว่าฉันต้องลบตัวอักษร 0-31 และ 127
มีฟังก์ชั่นหรือชิ้นส่วนของรหัสที่จะทำเช่นนี้ได้อย่างมีประสิทธิภาพ
คำตอบ:
หากควานหาของคุณเพิ่งลงจอดในปี 1963 และคุณต้องการตัวอักษร ASCII ที่พิมพ์ได้ 7 บิตคุณสามารถคัดลอกทุกอย่างตั้งแต่ 0-31 และ 127-255 ด้วยวิธีนี้:
$string = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $string);
มันตรงกับทุกอย่างในช่วง 0-31, 127-255 และลบออก
คุณล้มลงใน Hot Tub Time Machine และคุณกลับมาในยุคแปด หากคุณมี ASCII 8 บิตบางรูปแบบคุณอาจต้องการให้ตัวอักษรอยู่ในช่วง 128-255 ปรับง่าย - เพียงมองหา 0-31 และ 127
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
อายินดีต้อนรับกลับสู่ศตวรรษที่ 21 หากคุณมีสตริงที่เข้ารหัส UTF-8 คุณสามารถใช้/u
ตัวดัดแปลงบน regex ได้
$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);
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
การกำหนดเวลาใช้สำหรับการวนซ้ำ 10,000 ครั้ง แต่สิ่งที่น่าสนใจกว่าคือความแตกต่างสัมพัทธ์ มากถึง 512 ตัวฉันเห็น preg_replace เสมอชนะ ในช่วง 1-8kb, str_replace มีขอบเล็กน้อย
ฉันคิดว่ามันเป็นผลลัพธ์ที่น่าสนใจรวมถึงที่นี่ด้วย สิ่งสำคัญคือไม่ใช้ผลลัพธ์นี้และใช้เพื่อตัดสินใจว่าจะใช้วิธีใด แต่เพื่อเปรียบเทียบกับข้อมูลของคุณเองแล้วตัดสินใจ
คำตอบอื่น ๆ อีกมากมายที่นี่ไม่ได้คำนึงถึงตัวอักษร unicode (เช่นöäüßйȝîûηыეமிᚉ⠛) ในกรณีนี้คุณสามารถใช้สิ่งต่อไปนี้:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);
มีคลาสอักขระแปลก ๆ อยู่ในช่วง\x80-\x9F
(เหนือช่วงอักขระ ASCII 7 บิต) ที่เป็นตัวควบคุมทางเทคนิค แต่เมื่อเวลาผ่านไปได้ถูกนำไปใช้ในทางที่ผิดสำหรับอักขระที่พิมพ์ได้ หากคุณไม่มีปัญหาใด ๆ กับสิ่งเหล่านี้คุณสามารถใช้:
$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
'/[\x00-\x1F\x80-\xC0]/u'
ทำให้พวกเขาเหมือนเดิม; แต่ยังมีสัญลักษณ์ (F7) และการคูณ (D7)
\x7F-\x9F
หรือ
เริ่มต้นด้วย 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 ฯลฯ ดังนั้นตัวเลือกมากมายสำหรับการฆ่าเชื้อ (ดึงข้อมูล) และการตรวจสอบความถูกต้อง (คืนเท็จถ้าไม่ถูกต้องแทนที่จะลอกแบบเงียบ ๆ )
การฆ่าเชื้อ: http://php.net/manual/en/filter.filters.sanitize.php
การตรวจสอบความถูกต้อง: http://php.net/manual/en/filter.filters.validate.php
อย่างไรก็ตามยังคงมีปัญหาว่า FILTER_FLAG_STRIP_LOW จะตัดการขึ้นบรรทัดใหม่และการขึ้นบรรทัดใหม่ซึ่งสำหรับ textarea เป็นอักขระที่ถูกต้องสมบูรณ์ ... ดังนั้นฉันคิดว่า Regex บางคำตอบยังคงมีความจำเป็นในบางครั้งเช่นหลังจากตรวจสอบเรื่องนี้ ด้ายฉันวางแผนที่จะทำสิ่งนี้สำหรับ textareas:
$string = preg_replace( '/[^[:print:]\r\n]/', '',$input);
ดูเหมือนว่าจะสามารถอ่านได้มากกว่าจำนวน regexes ที่แยกออกตามช่วงตัวเลข
ง่ายกว่านี้:
$ 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;
}
เพื่อทำให้รุนแรงขึ้นปัญหาคือตารางเทียบกับเซิร์ฟเวอร์กับการเชื่อมต่อกับการแสดงผลของเนื้อหาเช่น กล่าวไว้ที่นี่เล็กน้อย
$s = preg_replace('/(\xF0\x9F[\x00-\xFF][\x00-\xFF])/', ' ', $s);
เพราะตัวละครอิโมจิทั้งหมดสับสนวุ่นวาย mysql
คุณสามารถใช้การแสดงปกติเพื่อลบทุกอย่างนอกเหนือจากตัวละครที่คุณต้องการเก็บไว้:
$string=preg_replace('/[^A-Za-z0-9 _\-\+\&]/','',$string);
แทนที่ทุกอย่างที่ไม่ใช่ (^) ตัวอักษร AZ หรือ az ตัวเลข 0-9, ช่องว่าง, ขีดล่าง, hypen, plus และเครื่องหมาย - ไม่มีอะไร (เช่นลบออก)
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);
สิ่งนี้จะลบอักขระควบคุมทั้งหมด ( http://uk.php.net/manual/en/regexp.reference.unicode.php ) ออกจาก\n
อักขระบรรทัดใหม่ จากประสบการณ์ของฉันตัวควบคุมเป็นตัวละครที่มักทำให้เกิดปัญหาการพิมพ์
/u
สำหรับ UTF-8 chars คุณช่วยอธิบายส่วนแรก(?!\n)
ทำอะไรได้บ้าง
หากต้องการตัดอักขระที่ไม่ใช่ ASCII ทั้งหมดออกจากสตริงอินพุต
$result = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $string);
รหัสนั้นจะลบตัวอักษรใด ๆ ในช่วงเลขฐานสิบหก 0-31 และ 128-255 เหลือเพียงตัวอักษรฐานสิบหก 32-127 ในสตริงผลลัพธ์ที่ฉันเรียก $ result ในตัวอย่างนี้
คำตอบของ @PaulDixon คือผิดทั้งหมดเพราะมันเอาพิมพ์ อักขระ ASCII ขยาย 128-255!ได้รับการแก้ไขบางส่วน ฉันไม่รู้ว่าทำไมเขายังต้องการลบ 128-255 จากชุด ASCII แบบ 7 บิต 127 ตัวอักษรเนื่องจากมันไม่มีอักขระ ASCII ที่ขยายเพิ่ม
แต่ในที่สุดมันก็สำคัญที่จะไม่ลบ 128-255 เพราะตัวอย่างเช่นchr(128)
( \x80
) คือเครื่องหมายยูโรใน ASCII 8 บิตและแบบอักษร UTF-8 จำนวนมากใน Windows แสดงเครื่องหมายยูโรและ Android เกี่ยวกับการทดสอบของฉันเอง
และจะฆ่าอักขระ UTF-8 จำนวนมากหากคุณลบ ASCII chars 128-255 ออกจากสตริง UTF-8 (อาจเป็นไบต์เริ่มต้นของอักขระหลายไบต์ 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 และตรวจสอบด้วยตัวเอง
เกี่ยวกับ:
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));
}
?>
ฉันแก้ไขปัญหาสำหรับ UTF8 โดยใช้https://github.com/neitanod/forceutf8
use ForceUTF8\Encoding;
$string = Encoding::fixUTF8($string);
regex ในคำตอบที่เลือกล้มเหลวสำหรับ 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;
จาก: UTF 8 String ลบอักขระที่มองไม่เห็นทั้งหมดยกเว้นขึ้นบรรทัดใหม่