Цікавий нюанс з пробілами при чищенні текстів функцією preg_replace
При чищенні текстів регулярними виразами в PHP я зіткнувся з цікавою проблемою - деякі прогалини ігнорувалися. Пошук і усунення проблеми відняло в мене не мало часу, був отриманий корисний досвід.
Завдання полягало в тому, щоб очистити порожні абзаци в самому початку тексту в безлічі статей, оскільки ці абзаци там не потрібні і псують загальний вигляд статті.
зміст:
- проводимо дослідження
- Допоможе HEX-редактор
- висновок
проводимо дослідження
Для виконання завдання з чищення шматків коду, що представляє порожні абзаци, я вирішив використовувати регулярні вирази (RegExp) в PHP. Простий функцією заміни підрядка тут не обійтися, оскільки варіантів і комбінацій може бути багато.
Ось деякі варіанти HTML коду, які були присутні в тексті і виводили порожні абзаци:
<P> </ p> <p> </ p> <p> & nbsp; & nbsp; </ p> <p> & # 160; </ p> <p> </ p>
Як бачимо, між тегами може бути пробіл, може бути його HTML-код, а також може і зовсім не бути ніякого символу. Частка таких рядків коду в текстах виконувалася регулярним виразом:
$ Txt = preg_replace ( '# ^ <p> (& nbsp; | s | & # 160;) + </ p> #is', '', $ original_text);
Статті які містили непотрібні порожні абзаци позбулися пустот, але в деяких порожні абзаци спочатку все ж залишилися, подивившись вихідний код HTML однієї з таких статей я побачив наступне:
<P> </ p>
Дивно ... два тега і кілька прогалин, можливо щось упущено. Запустив чистку наведеним вище регулярним виразом ще раз - нічого не змінилося.
Що ж це за містика? Скопіював цей шматок коду з пробілами в буфер обміну і закинув в конвертер Text-> Hex ( http://www.swingnote.com/tools/texttohex.php ), Отримую результат:
Hex Spaced: 3c 70 3e 20 20 20 20 20 3c 2f 70 3e
Не видно нічого незвичайного: "20" (x20) - це код звичайного пробілу, функція повинна була очистити цю строчку.
Вирішив написати регулярний вираз конкретно для цього випадку:
$ Txt = preg_replace ( '# ^ <p> x20 + </ p> #is', '', $ original_text);
Це регулярний вираз так і не очистило зазначену рядок (не замінить на порожню) - прогалини оповиті двома тегами залишилися на своєму місці.
Можливо що при копіюванні тексту з браузера в буфер обміну символи якось конвертуються, потрібно якось це все перевірити.
Допоможе HEX-редактор
Для з'ясування що ж представляє із себе ця загадкова рядок коду з двома тегами і пробілами, вирішив застосувати HEX-редактор.
Текст був збережений в файл за допомогою PHP-функції "file_put_contents". Для того, щоб переглянути текстовий файл в HEX-форматі, в нагоді програма під назвою "HxD".
HxD - це безкоштовний HEX редактор ( http://mh-nexus.de/en/hxd/ ), Програма маленького розміру, бінарний файл в декілька сотень кілобайт.
Відкривши в HxD раніше збережений в файл текст рядка я побачив наступне:
<P> </ p> 3C 70 3E A0 20 A0 A0 A0 3C 2F 70 3E
Виявилося що між тегами присутні символ з кодом A0 (xA0), а також один символ пробілу з кодом 20 (x20).
Подивившись в таблицю з кодами символів стало зрозуміло що це за символ з кодом xA0. Це той же самий пробіл тільки нерозривно:
Dec Hex Symbol HTML Number HTML name Description 160 A0 & # 160; & Nbsp; non-breaking space 32 20 & # 32; space
Доповнивши шаблон регулярного виразу кодом даного символу, функція виконала чистку як годиться:
$ Txt = preg_replace ( '# ^ <p> [xA0x20] + </ p> #is', '', $ original_text);
висновок
Не поспішаючи, я витратив кілька годин часу щоб розібратися з даними нюансом. Був отриманий цікавий досвід і проблема вирішена! Ось така ось магія ...
PS Роботи проводились на PHP 5.3;