Виправлення посилань на законодавство: епізод 1 (статті і частини)

опубліковано: 26.08.2017

Андрій Костенко

У правничих текстах часто вживаються посилання на норми нормативно-правових актів, в яких ключовим елементом є називання номерів статей, частин, пунктів, підпунктів, абзаців тощо. Загалом, прийнято записувати такі посилання в напрямі від конкретного до загального:
• частина 5 статті 12 Закону України "Про ...";
• пункт 3 частини 5 статті 12 Закону України "Про ...";
• підпункт 2 пункту 3 частини 5 статті 12 Закону України "Про ...";
• абзац 1 частини 4 статті 17 Закону України "Про ...";
тощо.

Але зустрічаються документи, в яких їх автори мають звичку записувати ці посилання навпаки, від загального до конкретного (тобто не "ч. 5 ст. 12", а "ст. 12 ч. 5"). Особливо це стосується судових рішень, що трошки засмучує. Адже проблема в тому, що при автоматизації аналізу подібних документів можуть не спрацьовувати алгоритми пошуку, збору, підрахунку та інших операцій з подібними посиланнями, які не враховують таку "несподіванку".

Наприклад, паттерн регулярного виразу /ч\.(\s| |)\d{1,4}(\s| |)ст\.(\s| |)\d{1,4}/gi, націлений на розпізнання посилань типу "ч. 5 ст. 12" не помітить посилання типу "ст. 12 ч. 5". Як наслідок, пошук та інші операції в такому тексті з таким паттерном будуть неповноцінними.

Звісно, можна використовувати більш складний паттерн
/(ч|ст)\.(\s| |)\d{1,3}(\s| |)(ст|ч)\.(\s| |)\d{1,4}/gi,
який знаходитиме й тип "ч. 5 ст. 12", й тип "ст. 12 ч. 5", або використовувати послідовно два паттерни для двох різних типів, і успішно знаходити всі посилання, але все ж може існувати потреба в тому, щоб автоматизувати приведення всіх посилань до правильного типу ДО здійснення їх змістовного аналізу:

Тому в цій статті я продемонструю алгоритм автоматизації виправлення у заданому тексті поганих посилань, які складаються з частин і статей.

перейти одразу до робочої моделі перейти одразу до вихідного коду

Для початку слід ближче познайомитися з регулярними виразами (жарг. "регулярками").
Їх можна вважати швейцарським ножем у сфері програмного аналізу текстів. Це набір спеціальних конструкцій, які дозволяють створювати паттерни (візерунки) – вимоги до шуканого образу тексту. Наприклад, за їх допомогою можна знаходити лише ті слова, після яких стоять числа із заданою кількістю цифр, перевіряти коректність телефонних номерів, веб-посилань, адрес e-mail тощо. Нижче я спрощено поясню лише ті елементи паттернів, які буду використовувати при вирішенні завдання цієї статті.

червоним кольором позначено пояснювані елементи

/ / – це межі паттерну, після правої межі йдуть прапори (наприклад, "g", "i");

/ /g – прапор "g" вказує програмі, що треба вести пошук всіх збігів у всьому тексті;

/ /i – прапор "i" вказує програмі, що не слід звертати увагу на регістр літер (тобто "А" і "а" будуть вважатися однаковими знахідками);

/частина/gi – це, власне, те, що шукаємо (у даному випадку будуть знайдені всі буквосполучення "частина", "ЧАСТИНА", "ЧаСтИнА" тощо);

\ – знак екранування символів, який дозволяє використовувати їх в іншій ролі, наприклад:
• "d" – це четверта літера англійської абетки, а "\d" – це позначення будь-якої цифри;
• а ось з крапкою навпаки: "." знайде будь-який символ (крім переводу рядка), а "\." – власне крапку;

/\d/ – знайде будь-яку цифру;

/\s/ – знайде будь-який пробільний символ;

/./ – знайде будь-який символ, крім переводу рядка;

{} – фігурні дужки використовуються, зокрема, для позначення кількості шуканих символів (наприклад, паттерн /\d{2,3}/ буде знаходити всі числа, що складаються з двох або трьох цифр, тобто, по суті, від 10 до 999, а також всі такі сполучення цифр, як 00, 01, 02 … 09 и 000, 001, 002 … 099);

(|) – така конструкція використовується для пошуку одного з декількох варіантів, вказаних обабіч вертикальної смуги (наприклад, паттерн /Євро-(2012|2016)/ буде знаходити як збіги "Євро-2012", так і збіги "Євро-2016").

Ось весь "будівельний матеріал" для нашої регулярки і оглянутий. Тепер покроково вибудуємо потрібний паттерн для пошуку поганих посилань типу "ст. 25 ч. 2".

1. //gi – пошук буде глобальним і регістронезалежним.

2. /ст\./gi – шукає буквосполучення "ст", після якого одразу йде крапка.

3. /ст\.(\s| |)/gi – шукає сполучення знаків "ст.", після якого йде одне з трьох: будь-який пробільний символ, на всяк випадок просто пробіл (так треба) або відсутність пробілів (буває і таке, що пробіли пропущені: "ст.4", "ст.110" и т.д.).

4. /ст\.(\s| |)\d{1,4}/gi – до попереднього додається потреба в наявності цифр в кількості від однієї до чотирьох (наприклад, в Цивільному кодексі України зараз 1308 статей).

5. тепер будуємо другу половину паттерну за таким самим принципом: літера "ч" + крапка + пробіли + цифри =
ч\.(\s| |)\d{1,3} .

6. між першою і другою частинами паттерну треба додати таке ж позначення пробілів або їх відсутності: (\s| |) .

7. з'єднуємо все це, і ось кінцевий результат:

/ст\.(\s| |)\d{1,4}(\s| |)ч\.(\s| |)\d{1,3}/gi

Ще раз треба наголосити, що паттерн регулярного виразу – це принципово важлива конструкція для вирішення поставленого завдання та йому подібних, до його побудови слід підходити дуже відповідально! До речі, даний паттерн не спрацює, якщо в посиланні буде більше одного пробілу між його будь-якими елементами (що нерідко трапляється). Тому треба зробити його ще більш страшним:

/ст\.(\s| |){1,9}\d{1,4}(\s| |){1,9}ч\.(\s| |){1,9}\d{1,3}/gi

Тобто тепер він буде знаходити і такі посилання, де між будь-якими елементами може стояти до 9 пробілів! Сподіваюсь, цього буде достатньо для більшості судових рішень.

Але й цього, насправді, ще недостатньо. Після літер може бути пропущена крапка, наприклад: "ст 8 ч 2", "ст. 8 ч 2", "ст 8 ч. 2". Щоб "не спіткнутися" і на цьому, треба ще посилити паттерн:

/ст(\.|)(\s| |){1,9}\d{1,4}(\s| |){1,9}ч(\.|)(\s| |){1,9}\d{1,3}/gi

А також слід захиститися від ситуацій, коли крапок стоїть більше однієї, використовуючи метасимвол +, який ідентичний конструкції "{1,+безкінечність}":

/ст(\.+|)(\s| |){1,9}\d{1,4}(\s| |){1,9}ч(\.+|)(\s| |){1,9}\d{1,3}/gi

Далі цей регулярний вираз покладається в основу скрипта, який діє за таким алгоритмом:
1) знаходить в заданому тексті всі погані посилання і виписує їх в окрему область пам'яті;
2) розділяє їх на складові (для цього також використовуються регулярні вирази);
3) міняє ці складові місцями і об'єднує їх в гарне (виправлене) посилання;
4) прибирає у виправлених посиланнях зайві пробіли і крапки (також можна прибрати це і в гарних посиланнях);
5) заміняє в заданому тексті всі раніше знайдені погані посилання на виправлені;
6) виводить новий текст.

Але навіть такий, здавалося б, потужний паттерн не враховує таких ситуацій:
1) коли трапляється стаття з позначкою, наприклад: "ст. 81" або "ст. 8-1";
2) коли наводиться декілька частин однієї статті, наприклад: "ст. 5 ч. 1, 2" або "ст. 5 ч.ч. 1, 2";
3) коли замість цифри "3" стоїть велика літера "З", що трапляється при оцифруванні текстів.

Як коректно впоратись і з такими ситуаціями, буде розказано в наступній статті.

перейти до робочої моделі перейти до вихідного коду

Знайшли помилку чи є що додати?
Пишіть на e-mail contact@legaltech.org.ua або сюди.