Фільтрація рядків з використанням автоматів h2>
Alexander Babaev p>
Необхідність фільтрації рядків
h2>
Строки використовуються дуже часто. А застосовне до
Інтернет-програмування можна сказати, що рядки використовуються постійно.
Будь-яка відповідь сервера - це рядок, запит клієнта - теж рядок. Робота з
XML-файлами - це знову робота з рядками, нехай і дуже формалізована.
Тому необхідно вміти швидко й ефективно обробляти рядкові дані.
Основна операція, яка використовується - це конкатенація (злиття). Вона
реалізована для всього, чого завгодно і зазвичай дуже прозора. Друга ж операція
- Це зміна рядків. І тут думки щодо того, що використовувати,
розходяться. p>
Стандартні методи фільтрації рядків
h2>
Для початку згадаємо, як відбувається робота з рядками
у звичайній програмі. Використовується кілька методів. Перший можна назвати
класичним. У цьому випадку для отримання результату використовуються стандартні
операції пошуку, заміни, конкатенації та видалення частин рядка. Такий метод
виправданий для швидкого вирішення найпростіших завдань, але як тільки потрібно
реалізувати що-небудь більш-менш складне, миттєво починаються проблеми.
Крім того, цей спосіб зовсім не масштабується і дуже складно змінюється. P>
Другий метод - використання регулярних виразів
(регекспов). Детально розглядати їх не має сенсу, є відмінна книга Дж.
Фрідл [1], в якій все докладно описано, в тому числі й застосовне до Java.
Переваги підходу полягають в тому, що регулярні вирази
стандартизовані, володіють величезними можливостями і дуже компактно
записуються. Тобто якщо ви навчилися використовувати регулярні вирази в
Perl або PHP, вам нічого не варто використовувати їх в Java (хоча все одно
доводиться щоразу з'ясовувати нюанси реалізації). Самий головний недолік --
складність, яка виростає з величезної потужності регулярних виразів.
Прості регекспи може зрозуміти навіть початківець, але більш-менш
складні починаючому вже не по зубах. Регекспи ж, подібні представленому в
лістингу 1, не зрозуміє ніхто навіть при дуже великому бажанні (в лістингу
представлена приблизно восьма частина регулярного виразу, призначеного для
перевірки коректності e-mail адреси і його відповідності RFC). Втім, є
люди, які «читають» регулярні вирази «з листа». Даний приклад не зовсім
показовий у тому сенсі, що і програма, що виконує аналогічну функцію,
буде дуже і дуже складна. Але є і набагато більш прості завдання, (приклади
таких завдань будуть розглянуті нижче), в яких регулярні вирази
використовувати так само незручно. p>
Лістинг 1.Часть регулярного виразу,
призначеного для перевірки коректності e-mail адреси, відповідності його RFC. p>
^ [ p>
*/ p>
public boolean isEnabled (IFilter aFilter); p>
/** p>
* Ініціалізація параметрів групи. Цей метод використовується в p>
* Основному для встановлення параметрів правила при завантаженні p>
* Конфігурації фільтра з XML. P>
* @ Param aParameters карта параметрів p>
*/ p>
public void setParameters (Map aParameters); p>
) p>
Для спрощення роботи з системою написано кілька
класів, що допомагають при створенні нових фільтрів і правил. Такими класами
є AbstractFilter і AbstractRule. Перший описує всі методи,
необхідні для роботи стандартного фільтра. Тому для того, щоб створити
потрібний фільтр, можна просто створити клас-спадкоємець AbstractFilter і в
конструкторі викликати метод addRule (), додавши все необхідне в потрібній послідовності
(лістинг 8). p>
Лістинг
8. Складання фільтра з окремих правил. p>
public
class WikiFilter extends AbstractFilter p>
( p>
public WikiFilter (int aMaxWordLength, int
aMaxStringLength) p>
( p>
// заміна <на < p>
addRule (new ReplaceLeftTagBracketRule ()); p>
// заміна & на & p>
addRule (new
ReplaceAmpersandTagBracketRule ()); p>
//
правило екранування - для можливості виведення спецсимволів p>
addRule (new EkranRule ()); p>
//Правило заміни http:// ... - Посиланнями p>
addRule (new AnchoringRule (aMaxWordLength )); p>
... ... ... p>
//Правило розбивання довгих слів пробілами p>
addRule (new
BreakWordsRule (aMaxWordLength )); p>
//Правило «обрізання» довгих рядків p>
addRule (new MaxLengthRule (aMaxStringLength )); p>
) p>
) p>
Після цього обробка рядка даними фільтром
являє собою тривіальну завдання: p>
String
result = p>
new WikiFilter (maxWordLength,
maxStringLength). process (sourceString); p>
AbstractRule визначає методи setEnabled () і
isEnabled (), однакові для більшості фільтрів. p>
public
abstract class AbstractRule implements IRule p>
( p>
//Це поле зроблено ThreadLocal для того, щоб можна було одним
фільтром p>
//Обробляти кілька рядків одночасно p>
private ThreadLocal _enabledThreadLocal =
new ThreadLocal () p>
( p>
protected Object initialValue () ( p>
// за замовчуванням правило включається p>
return Boolean.TRUE; p>
) p>
); p>
public void setParameters (Map aParameters)
throws FilterException p>
( p>
//Для багатьох правил цей метод не використовується, тому робимо p>
//Його необов'язковим p>
) p>
public void initialize () p>
( p>
//Так само, як і setParameters - робимо цей метод необов'язковим p>
) p>
public void setEnabled (boolean aEnabled) p>
( p>
_enabledThreadLocal.set (Boolean.valueOf (aEnabled )); p>
) p>
public boolean isEnabled () p>
( p>
return ((Boolean)
_enabledThreadLocal.get ()). equals (Boolean.TRUE); p>
) p>
) p>
Є можливість відключати деякі правила
безпосередньо в процесі роботи фільтру або між виконаннями методу
process (). Можна також динамічно змінювати фільтр або налаштовувати його. При
цьому не потрібно перекомпіляції код або самого фільтра. p>
Також створений допоміжний клас
CustomFilterFromXML, який дозволяє завантажити конфігурацію фільтра з
XML-файл і автоматично її оновлює при зміні XML-файлу. P>
Застосування
p>
Метод фільтрації рядків, представлений у цій статті,
можна застосувати не тільки в вузькоспеціалізованої області роботи з інтернет-текстами.
Створюючи різні правила, легко створювати рядки, які будуть керувати,
наприклад поведінкою програми. Можливості необмежені. Описана тут
система називається JFilter і розповсюджується вільно, її сторінка в
інтернеті: http://blog.existence.ru/exception/.products.JFilter.
Там можна знайти як бібліотеку у форматі jar, так і вихідні тексти з
документацією. У додатку наведено код інтерфейсів фільтра та правила, які
є основними інтерфейсами системи. JFilter використовується в системі блогів
JDnevnik [6] і ще в декількох проектах. P>
Правила, що входять в постачання
p>
Всі стандартні правила написані в стилі, допускає
одночасну обробку фільтром кількох рядків, завдяки чому їх можна використовувати
в многопоточной середовищі. p>
Стандартні правила
(jfilter.rules.general) p>
BreakWorksRule - розбиває
довгі слова пробілом. p>
EkranRule - правило
екранування спецсимволів. p>
MaxLengthRule - правило,
яке обмежує довжину рядків. p>
HTML-правила
(jfilter.rules.html) p>
AnchoringRule - заміна
тексту, що починається з http:// (або аналогів) і закінчується пробілом,
HTML-посиланням. P>
MailRule - заміна тексту,
укладеного в прогалини і містить символ «@», HTML-посиланням. p>
емотікон
(jfilter.rules.smiles) p>
PreSmiler - заміна
позначень емотікон («:-)», «;)» і так далі) на їх стандартні
позначення для обробки SmilesRule'ом. p>
SmilesRule - заміна
одиночних слів, укладених у парні двокрапки «::», HTML-картинками. p>
Транслітерація
(jfilter.rules.transliteration) p>
Lat2RusTransliterationRuleGroup
- Транслітерація. Відповідає ISO та ГОСТ (тобто можна писати як по
ГОСТом, так і позначеннями ISO; поки конфліктів такого варіанту я не
виявив). p>
Типографіка
(jfilter.rules.typografica) p>
AbbreviationsRule - заміна
(c), (p), (r), (tm) відповідними HTML-символи. p>
HellipRule - заміна трьох
точок підряд символом «три крапки». p>
LongDashRule - Заміна
символу «мінус», обрамленого пробілами символом «тире». p>
QuotesRule - заміна «знака
дюйма »коректними лапками для російської мови. p>
Вікі-форматування
(jfilter.rules.wacko) p>
AnchorRule - створення
посилань у вигляді ((link )). p>
BlockquoteRule - цитата
(>> текст >>). p>
BoldRule - виділення
напівжирним шрифтом (** напівжирний **). p>
HeaderRule - заголовок
(== заголовок ==). p>
ItalicRule - виділення
курсивом (//курсив //). p>
MonospaceRule - виділення
моноширинних шрифтом (# # моно ##). p>
NoteRule - виділення
зауваження (span class = "note "). p>
ParagraphRule - Робота з
перекладами рядки (одиночний переклад рядка -
, дві підряд --
). p>
PreformattedRule --
виділення попередньо відформатованого тексту (%% вже форматрованний
текст %%). p>
ReplaceAmpersandTagBracketRule
- Заміна символу "&" відповідним HTML-аналогом (&). p>
ReplaceLeftTagBracketRule --
заміна символу "<" відповідним HTML-аналогом (<). p>
SmallRule - виділення
дрібним шрифтом (+ + дрібний ++). p>
StrikeRule - виділення
перекресленням (- перекреслений -). p>
SubscriptRule - виділення
нижнім індексом (vvніжній індексvv). p>
SuperscriptRule - виділення
верхнім індексом (^ ^ верхній індекс ^^). p>
UnderlineRule - виділення
підкресленням (__подчерківаніе__). p>
Таблиця 1. Стандартні правила. p>
Порівняння роботи різних типів обробки рядків
p>
Властивість p>
Класичний спосіб p>
Регулярні вирази p>
Фільтрація p>
Простота реалізації p>
Просто p>
Дуже складно p>
Складно p>
Можливості зміни p>
Для простих завдань - дуже
великі, для складних - дуже складні p>
Тільки разом з
перекомпіляції вираження p>
Максимальні p>
Простота використання p>
Дуже просто p>
Просто для тих, хто
витратив багато часу на навчання p>
Дуже просто p>
Швидкість роботи p>
Швидко на простих
варіантах, звичайно повільно на складних, сильно залежить від реалізації p>
Швидко, якщо правильно
використовувати p>
Швидко p>
Таблиця 2. Порівняння різних типів обробки рядків. p>
Висновок
p>
Хочеться відзначити, що бібліотека JFilter продовжує
розвиватися, на даний момент реалізовано дуже багато, але далеко не всі з
того, що хотілося б реалізувати. У найближчому майбутньому передбачається написання
додаткових правил для класичної, «паперової» типографіки, які
допомагали б редакторів, та верстальника самих звичайних, паперових
книг/журналів/газет. p>
Список b> b> літератури b> p>
Фрідл Дж., Mastering Regular
Expressions. Пітер, 2003 рік. p>
http://is.ifmo.ru, Санкт-Петербурзький Державний
університет інформаційних технологій, механіки і оптики, кафедра «Технології
програмування ». p>
Бабаєв А. "," МИР ПК - ДИСК. 2003. № 12, Транслітерація і
як правильно її треба програмувати. p>
http://is.ifmo.ru/projects/bone/ - створення скелетної
анімації на основі автоматного програмування. p>
http://wackowiki.com/projects/WackoFormatter
-Бібліотека для форматування тексту WackoFormatter. p>
http://blog.existence.ru/exception/.products.JDnevnik
- Система блогів JDnevnik. p>
Для підготовки даної роботи були використані
матеріали з сайту http://www.rsdn.ru/
p>