ตัวอักขระพื้นที่ว่างหรือ space นั้นความจริงมีหลายรูปแบบ เช่น Non-breaking space, Em space, Thin space, และอื่นๆ ฯลฯ. เราอาจจะเรียกว่าเป็นอักขระพื้นที่ว่างแบบ unicode ก็ได้ แต่เพราะความที่เป็นอักขระที่แตกต่างกันกับการเคาะ space บนคีย์บอร์ดเฉยๆ ดังนั้นมันจึงมีปัญหาในการเปรียบเทียบด้วยเครื่องหมาย ==
หรือ ===
ดังจะสามารถทดลองได้จากโค้ดต่อไปนี้.
$space = ' ';
$spaces = [
"\u{0020}",// normal space
"\u{00A0}",// no-break space
"\u{2003}",// em space
"\u{2009}",// thin space
"\u{2002}",// en space
"\u{200A}",// hair space
];
foreach ($spaces as $eachSpace) {
var_dump($eachSpace);
var_dump($space === $eachSpace);
if ($space !== $eachSpace) {
echo '<span style="color: red;">No matched.</span><br>';
} else {
echo '<span style="color: green;">Matched.</span><br>';
}
echo '<br>';
}
จะพบว่าผลลัพธ์ของมันจะตรง (Matched) แค่รายการเดียว นอกนั้นจะไม่ตรง (No matched) ทั้งหมด เพราะตัวอักขระนั้นต่างกัน แม้ตาเราจะมองเห็นเป็นพื้นที่ว่างเหมือนกันก็ตาม.
แม้แต่การนับจำนวนอักขระก็จะต่างกัน ดังโค้ดต่อไปนี้.
// $spaces โปรดนำมาใช้จากโค้ดด้านบน
foreach ($spaces as $eachSpace) {
var_dump($eachSpace);
echo 'strlen: ' . strlen($eachSpace) . '<br>';
echo 'mb_strlen: ' . mb_strlen($eachSpace) . '<br>';
echo '<br>';
}
จะพบว่า strlen()
จะนับได้ 1, 2, และที่เหลือเป็น 3 ทั้งหมด ในขณะที่ mb_strlen()
จะนับได้ตรงกันทั้งหมดคือ 1.
การแก้ปัญหา
ให้ทำการแปลงอักขระด้วยวิธี normalize โดยใช้โค้ด \Normalizer::normalize($string, Normalizer::FORM_KD);
.
// $spaces โปรดนำมาใช้จากโค้ดด้านบน
foreach ($spaces as $eachSpace) {
var_dump($eachSpace);
$normalized = \Normalizer::normalize($eachSpace, Normalizer::FORM_KD);
var_dump($space === $normalized);
if ($space !== $normalized) {
echo '<span style="color: red;">No matched.</span><br>';
} else {
echo '<span style="color: green;">Matched.</span><br>';
}
echo '<br>';
}
ผลลัพธ์จากโค้ดด้านบนนี้จะเป็น Matched ทั้งหมด เพราะหลังจากที่ทำการ normalize เสร็จแล้ว อักขระพื้นที่ว่างที่เป็นรูปแบบต่างๆ ก็จะตรงกับตัวอักขระพื้นที่ว่าง (space) ที่เกิดจากการเคาะ space bar บนคีย์บอร์ดของเรา. ส่วนวิธีการนับจำนวนอักขระนั้น ยังคงยืนยันให้ใช้ mb_strlen()
ตามเดิมเพราะสามารถนับจำนวนตัวอักษระได้ถูกต้องกว่า ไม่ใช่นับจากจำนวนไบต์.