Перетворення тексту за допомогою регулярних виразів - Статті - Delphi.int.ru

Автор: Вадим До

Я пишу ці статті в MS Word з тієї причини, що він (Word) перевіряє орфографію і граматику. Але у нього є один істотний недолік. Статті в Інтернет публікуються в форматі HTML і, хоча MS Word і вміє конвертувати, але робить це огидно. Сторінка, яка могла б займати 3-4 кілобайт, має вагу 20-30. Найприкріше, що все можна вичистити "ручками", а зовнішній вигляд сторінки і не зміниться.

Чистити текст будемо за допомогою давно відомого методу - регулярних виразів.

Для того, що б продовжити роботу нам потрібно:

- Delphi 7, 2005, 2006, 2007 версії. На молодших версіях повинно працювати, але не гарантую;
- Завантажити бібліотеку для регулярних виразів з сайту http://www.regexpstudio.com/RU/TRegExpr/TRegExpr.html . Якщо точніше, то http://www.regexpstudio.com/Downloads/regexpr_RU.zip і завантажити (це опціонально) утиліту для тестування регулярних виразів http://www.regexpstudio.com/RU/RegExpStudio.html . Все це також можна взяти в архіві до статті.
- Ну і напій до смаку :-)

Робітничий клас

Запускаємо Delphi і відразу додаємо ще один юніт (File -> New -> Unit). Зберігаємо проект. "Unit2" я зберігаю під ім'ям "ClassTextTransf.pas". "Unit1" як "Main.pas". А сам проект як "HTMLClean.dpr". Тепер з архіву винесемо файл "Source \ RegExpr.pas" і скопіюємо його в папку до нашого проекту.

Повертаємося до файлу ClassTextTransf. Після рядка interface підключаємо потрібні нам файли - uses SysUtils, Classes, RegExpr;

З наступного рядка починаємо писати заготовку для нашого класу.

type TTextTransf = class private FText: string; FFileName: string; public constructor Create (fileName: string); destructor Destroy; override; procedure Load; procedure Save; procedure Erase (Expr: string); end;

Тепер натискаємо Ctrl + Shift + C і Delphi допише заготовки для коду.
Деякі коментарі. FText - змінна, яка зберігає власне сам текст. Load і Save завантажує текст з файлу і відповідно зберігає. Файл вказується в конструкторі. Робочий метод у нас Erase. Він отримує рядок - регулярний вираз, щоб знати, що замінювати на порожній рядок, адже ми видаляємо "зайвий текст". Його реалізацію ми і розглянемо. Всі інші методи прості і їх реалізацію можна підглянути в доданому архіві.

procedure TTextTransf. Erase (Expr: string); var r: TRegExpr; begin r: = TRegExpr. Create; try r. Expression: = Expr; FText: = r. Replace (FText, '', false); finally r. free; end; end;

Розглянемо цей код докладніше. На початку ми створюємо екземпляр класу (тобто об'єкт), який вміє обробляти регулярні вирази. Далі передаємо саме регулярний вираз і викликаємо функцію Replace. Її параметри наступні: перший - рядок, в якій ми будемо видаляти текст, другий - на який текст будемо замінювати. Так як ми видаляємо, то у нас це порожній рядок. Третій параметр поки залишаємо False. Він розширює функціональність і нам поки не потрібен. Далі записуємо отриманий текст назад в нашу змінну. Як складати регулярні вирази - розберемося пізніше.

інтерфейс

Тепер пишемо інтерфейсний код - юніт main.pas. Для початку накидаємо компоненти. У мене вийшло так:

У мене вийшло так:

Код кнопки "Огляд ..." виглядає просто:

procedure TForm1. btnBrowseClick (Sender: TObject); begin if not OpenDialog1. Execute then exit; edit1. Text: = OpenDialog1. FileName; end;

Тут поки нічого незвичайного.

Тепер для кнопки "Обробити". Спочатку потрібно підключити наш юніт з класом. Це просто. Меню File - Use unit і вибираємо наш юніт (він там єдиний).

І пишемо обробник для кнопки:

procedure TForm1. btnWorkClick (Sender: TObject); var tt: TTextTransf; begin tt: = TTextTransf. Create (Edit1. Text); try tt. Load; // тут ми будемо вставляти код обробки tt. Save; finally tt. free; end; end;

Як видно - нічого складного. Створили об'єкт, завантажили текст і зберегли результат. Код обробки, який власне виконує основну роль, поки опущений.

Отже, що ж треба видаляти? В подальшому розповіді я припускаю, що ви знайомі з базовим синтаксисом HTML. Створимо в MSWord текст на кілька сторінок (я експериментував на даній статті) і збережемо в html форматі. Також зробіть резервну копію або трохи модіфіціруqnt метод Save, щоб він не видаляв старий файл. Тепер відкриємо сам збережений файл. Як видно, MS Word дуже любить вставляти тег span. Іноді по суті, іноді за фактом перемикання розкладки, а іноді як йому в голову прийде. Якщо видалити їх, жоден браузер нічого не помітить (ну не зовсім все, але детальніше розбиратися - це вже інша історія). У нас є що відкриває тег і закриває. З останнім все зрозуміло - він однаковий і можна було б видалити і звичайним пошуком-заміною. В цьому випадку регулярний вираз буде просте - <\ / span>. Тільки перед слешем я поставив зворотний слеш. Справа в тому, що слеш є спецсимволи і щоб все працювало, символи треба "екранувати". До зарезервованим символам також відносяться квадратні дужки, крапка, плюс, кришка "^" і деякі інші. Перевіримо наш код. Вставимо на місце коментаря рядок tt.Erase ( '<\ / span>');

Запускаємо, обробляємо. Потім порівнюємо. Повинно працювати.

Тепер складніше. Треба видалити відкриває тег. Тут можуть бути різні варіанти. Але для початку треба спробувати описати словами. У мене виходить десь так: "спочатку кутова дужка, потім текст span потім будь-які символи крім закриває дужки і власне сама закриває дужка». Мовою регулярних виразів це виглядає так:

<span [^>] *>

Конструкція [^>] означає будь-який символ окрім кутовий закриває дужки. Якщо написати [abc], то це буде будь-який символ a, b або c. Конструкція виду [az] - будь-яка мала літера латинського алфавіту. Конструкція виду [^ 0-9] - все символи, крім цифр.

Зірочка (*) означає, що таких символів може бути 0 або більше. Якщо поставити +, то це буде означати, що повинен бути хоча б один символ.

Якщо тепер додати ще один рядок в наш код, то html очищається на 25%, а це вже непогано!

Наступний хід - замінити конструкції виду "<p class = MsoNormal>" на просто "<p>". Наш клас не вміє робити таку заміну. Але ми додамо ще один метод. Назвемо його Replace (FromText, ToText: string);

Якщо придивитися, то можна помітити, що наш попередній метод є окремим випадком цього. Erase (s) еквівалентно Replace (s, ''). Тому додамо новий метод, скопіюємо туди код з методу Erase і поправимо його. Те-є у нас вийде так:

procedure TTextTransf. Replace (FromText, ToText: string); var r: TRegExpr; begin r: = TRegExpr. Create; try r. Expression: = FromText; FText: = r. Replace (FText, ToText, false); finally r. free; end; end; procedure TTextTransf. Erase (Expr: string); begin Replace (Expr, ''); end;

Запитайте, а в чому ж принадність? А в тому, що нам не потрібно змінювати код основного юніта! Правильно спроектований клас приховує функціональність всередині і при оптимізації код, який використовує наш клас, не помітить змін. Також це зручно для поділу праці. Потрібно тільки домовитися про інтерфейс класів.

Тепер код заміни для нашої рядки буде виглядати просто:

tt. Replace ( '<p \ sclass = MsoNormal>', '<p>');

Тут тільки одна особливість - пробіл потрібно записати у вигляді \ s.

MS Word любить вставляти коментарі в текст, щоб потім йому було "легше". Але браузеру ці коментарі ні до чого. Здавалося б, все просто - беремо регулярний вираз "<! -. + ->". Але спробуйте застосувати його - щось багато віддалилося ... І дійсно, відкривши, ви побачите, що тексту віддалилося багато. Справа в тому, що за замовчуванням регулярні вирази працюють в "жадібному режимі". Те-є, коли під маску потрапляє кілька варіантів, то вони намагаються захопити "побільше". Нам це тільки заважає, тому ми відключимо. Це всього один рядок.

tt. Erase ( '<! [If! Vml]>'); tt. Erase ( '<! [Endif]>');

Ці рядки видалять щось не зовсім мені зрозуміле, але заважає нормальному відображенню зображень в браузері. Найцікавіше, що вони заважають тільки Internet Explorer'у. Іншим браузерам цей код - не перешкода.

Подивимося тепер на дивний текст після тега html в самому верху. Вже дуже багато там інформації. Вона потрібна, щоб у html документів, створених Word'ом відображалася трохи інша іконка і саме Word викликався при спробі редагування. Нам це не потрібно. Тут код простий:

tt. Replace ( '<html [^>] *>', '<html>'); tt. Erase ( '<meta \ sname \ = [^>] *>');

Тепер додамо трохи "краси". Після наших вилучень залишилося безліч порожніх рядків. Видалимо їх. Для цього будемо використовувати вираз Replace ( '\ n \ s * \ n', ''); У класі я оформив це у вигляді додаткового методу.

Після всіх маніпуляцій мені вдалося вичистити текст більш ніж в 2 рази. У ньому, звичайно, є ще місце для ручної обробки, але в цілому дуже непогано. У коді ви знайдете кілька додаткових рядків для оцінки продуктивності.

Безсумнівним плюсом вивчення регулярних виразів буде те, що вони використовуються в багатьох інших мовах, таких як Perl, PHP. Ця бібліотека сумісна з Perl'овской реалізацією і тому літератури в Інтернеті предостатньо.

Файли до статті »

Автор: Вадим До

Стаття додана: 24 листопад 2007

Наступна стаття: Знайомство з SQLite »

Рейтинг статті: 5.00 Голосів: 3 Ваша оцінка:

Увійдіть / авторизуйтесь,
щоб оцінювати статті.

Для вставки посилання на цю статтю на іншому сайті використовуйте наступний HTML-код:

Посилання для форумів (BBCode):

Швидка вставка посилання на статтю в повідомленнях на сайті:
{{a: 42}} (буква a - латинська) - тільки адреса статті (URL);
{{стаття: 42}} - повноцінна HTML-посилання на статтю (текст посилання - назва статті).

Поділіться посиланням в соціальних мережах:

Поділіться посиланням в соціальних мережах:

Репутація: +2

mirt.steelwater (13 грудня 2010, 18:21):

регулярні вирази - потужна річ! дякую, не знав, що вони є в Дельфи. а чи немає в цих класах простих механізмів для відображення BBcode в компонентах типу TRichedit?

Залишати коментарі до статей можуть тільки зареєстровані користувачі.

Отже, що ж треба видаляти?
А чи немає в цих класах простих механізмів для відображення BBcode в компонентах типу TRichedit?