1
0
mirror of https://github.com/Nivanchenko/tokenizer.git synced 2024-11-21 17:17:13 +02:00
This commit is contained in:
Nikita Ivanchenko 2024-07-06 15:52:03 +03:00
parent 13b11788ea
commit fd78275e87
23 changed files with 782 additions and 132 deletions

15
.github/workflow/release.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: Публикация релиза
on:
release:
types:
- published
workflow_dispatch:
jobs:
release:
uses: autumn-library/workflows/.github/workflows/release.yml@main
with:
package_mask: "tokenizer-*.ospx"
secrets:
PUSH_TOKEN: ${{ secrets.PUSH_TOKEN }}

37
.github/workflow/testing.yml vendored Normal file
View File

@ -0,0 +1,37 @@
# MIT License
# Copyright (C) 2020 Tymko Oleg <olegtymko@yandex.ru> and contributors
# All rights reserved.
name: Тестирование
# Любой пуш и pr в проекте
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
oscript_version: ['dev', 'stable']
steps:
# Загрузка проекта
- name: Актуализация
uses: actions/checkout@v2
# Установка OneScript конкретной версии
- name: Установка OneScript
uses: otymko/setup-onescript@v1.3
with:
version: ${{ matrix.oscript_version }}
# Установка зависимостей пакета
- name: Установка зависимостей
run: |
opm install opm
opm install -l --dev
# Задача тестирования, в результате ожидается успешное выполнение
- name: Тестирование
run: oscript ./tasks/test.os

5
.gitignore vendored
View File

@ -1,2 +1,5 @@
.vscode/
build/
build/
.DS_Store
*.ospx
out/

166
README.MD Normal file
View File

@ -0,0 +1,166 @@
## tokenizer
Токенизатор - простой пакет для разбиения строки на токены. Задача, которую он решает - разбиение строки на токены, по определенной спецификации.
### Примеры использования
Разбиение простой строки `1,2,3` на токены:
```bsl
Строка = "1,2,3";
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенЧисло());
Спека.Добавить(Новый СпецификацияТокенСимвол(",", "Запятая"));
Токенизатор = Новый Токенизатор(Спека);
Токенизатор.Инит(Строка);
Результат = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Результат.Добавить(Токенизатор.СледующийТокен());
КонецЦикла;
```
В результате выполнения этого кода массив `Результат` будет содержать три элемента типа с типом `Токен`.
### API
#### API объекта `Токен` следующий:
1. `Значение()` - возвращает значение токена.
2. `ТипТокена()` - возвращает тип токена.
3. `Начало()` - возвращает позицию токена в тексте.
4. `Размер()` - возвращает длину токена в тексте.
#### API объекта `Токенизатор` следующий:
1. `Инит(Строка)` - инициализирует токенизатор строкой.
2. `СледующийТокен()` - возвращает следующий токен.
3. `ЕстьЕщеТокены()` - возвращает `Истина`, если есть еще токены.
В конструктор `Токенизатор` передается спецификация токенов. Спецификация токенов - это массив объектов, реализующих интерфейс `СпецификацияТокена`.
Интерфейс `СпецификацияТокена` описывает следующие методы:
```bsl
Функция Проверить(Знач Строка) Экспорт
Если УдалосьНайтиТокенВСтроке Тогда
Возврат Новый Структура("Значение, Размер", "ЗначениеТокена", ДлинаТокена);
КонецЕсли;
Возврат Неопределено;
КонецФункции
Функция ТипТокена() Экспорт
Возврат "МойКастомныйТипТокена";
КонецФункции
```
### "Типовые" токены
Поставляемые вместе с пакетом спецификации токенов:
1. `СпецификацияТокенСимвол` - спецификация токена, который содержит один символ. В конструктуор передается символ и тип токена.
2. `СпецификацияТокенЧисло` - спецификация токена, который содержит целое число.
3. `СпецификацияТокенСтрока` - спецификация токена, который содержит строку. В конструктор передается экранирующий внутренние ковычки символ. Поддерживаемые экранируемые символы: `\`, `""""`.
4. `СпецификацияТокенИдентификатор` - спецификация токена, который содержит идентификатор, т.е. строка начинающаяся с буквы и содержит буквы и цифры.
5. `СпецификацияТокенПробелы` - спецификация токена, который содержит пробел. В конструктор передается флаг, который указывает, нужно ли пропускать пробелы или нет.
6. `СпецификацияТокенРегулярноеВыражение` - спецификация токена, который содержит строку, соответствующую регулярному выражению. В конструктор передается регулярное выражение и тип токена.
### Пример токенизации и парсинга журнала регистрации
`small.lgp`
```
1CV8LOG(ver 2.0)
758d6f0a-476f-468b-80ac-48773092049c
{20221110000049,N,
{2444a6a24da10,3d},1,1,1,1803214,81,I,"Первое событие",599,
{"U"},"Представление данных",1,1,9,3,0,
{0}
},
{20221110000049,U,
{2444a6a24da10,3d},1,1,1,1803214,81,E,"Второе ""событие""
многострочное ",599,
{"U"},"Представление данных2",1,1,9,3,0,
{2,1,31,2,31}
}
```
`ПарсерСкобки.os`
```bsl
Перем Токенизатор;
Перем ПрошлиЗаголовок;
Процедура ПриСозданииОбъекта(Лексер)
Токенизатор = Лексер;
ПрошлиЗаголовок = Ложь;
КонецПроцедуры
Функция Распарсить() Экспорт
ТекущийМассив = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Токен = Токенизатор.СледующийТокен();
Если ПрошлиЗаголовок = Ложь И Не Токен.ТипТокена() = "Открыть" Тогда
Продолжить;
КонецЕсли;
ПрошлиЗаголовок = Истина;
Если Токен.ТипТокена() = "Открыть" Тогда
ТекущийМассив.Добавить(Распарсить());
Продолжить;
КонецЕсли;
Если Токен.ТипТокена() = "Идентификатор"
ИЛИ Токен.ТипТокена() = "Число"
ИЛИ Токен.ТипТокена() = "Строка" Тогда
ТекущийМассив.Добавить(Токен.Значение());
КонецЕсли;
Если Токен.ТипТокена() = "Закрыть" Тогда
Возврат ТекущийМассив;
КонецЕсли;
КонецЦикла;
Возврат ТекущийМассив;
КонецФункции
```
`Main.os`
```bsl
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенПробелы(Истина));
Спека.Добавить(Новый СпецификацияТокенСимвол("{", "Открыть"));
Спека.Добавить(Новый СпецификацияТокенСимвол("}", "Закрыть"));
Спека.Добавить(Новый СпецификацияТокенСимвол(",", "Запятая"));
Спека.Добавить(Новый СпецификацияТокенРегулярноеВыражение(Новый РегулярноеВыражение("(1CV8LOG)|(\(\w+ \d.\d\))"), "Версия"));
Спека.Добавить(Новый СпецификацияТокенРегулярноеВыражение(Новый РегулярноеВыражение("[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$"), "Гуид"));
Спека.Добавить(Новый СпецификацияТокенРегулярноеВыражение(Новый РегулярноеВыражение("[\da-z]+"), "Идентификатор"));
Спека.Добавить(Новый СпецификацияТокенСтрока());
Спека.Добавить(Новый СпецификацияТокенЧисло());
Спека.Добавить(Новый СпецификацияТокенСимвол(Символы.ПС, "ПереносСтроки"));
Токенизатор = Новый Токенизатор(Спека);
ЧтениеТекста = Новый ЧтениеТекста("small.lgp");
Текст = ЧтениеТекста.Прочитать();
ЧтениеТекста.Закрыть();
Токенизатор.Инит(Текст);
Скобарь = Новый ПарсерСкобки(Токенизатор);
Результат = Скобарь.Распарсить();
```
Результатом парсинга будет массив, содержащий записи ЖР, каждая запись - массив, содержащий поля записи. С поддержкой вложенности массиов.

18
packagedef Normal file
View File

@ -0,0 +1,18 @@
////////////////////////////////////////////////////////////
// Описание пакета для сборки и установки
// Полную документацию см. на hub.oscript.io/packaging
//
Описание.Имя("tokenizer")
.Версия("1.0.0")
.Автор("Nikita Ivanchenko")
.АдресАвтора("https://github.com/Nivanchenko")
.Описание("Это очень хороший и нужный пакет программ")
.ВерсияСреды("1.9.1")
.ВключитьФайл("src")
.ВключитьФайл("tests")
.ВключитьФайл("tasks")
.ВключитьФайл("README.md")
.ВключитьФайл("packagedef")
;

View File

@ -1,79 +0,0 @@
Перем _Строка;
Перем _Токенизатор;
Перем _ТекущийТокен;
Перем _Спецификация;
Процедура ПриСозданииОбъекта()
_Токенизатор = Новый Токенизатор();
_Строка = "";
_Спецификация = Новый Массив();
КонецПроцедуры
Процедура ДобавитьСпецификацию(Спецификация) Экспорт
// Todo: добавить проверку на дубли
// Todo: добавить проверку на интерфейс.
_Спецификация.Добавить(Спецификация);
КонецПроцедуры
Функция Распарсить(Строка) Экспорт
Если _Спецификация.Количество() = 0 Тогда
Ошибка("Не задана спецификация токенов");
КонецЕсли;
_Строка = Строка;
_Токенизатор.Инит(Строка, _Спецификация);
_ТекущийТокен = _Токенизатор.СледующийТокен();
Возврат Программа();
КонецФункции
Функция Программа()
Возврат Новый Структура("Тип, Тело", ТипыТокенов.Программа, Литерал());
КонецФункции
Функция Литерал()
Если _ТекущийТокен.Тип = ТипыТокенов.Число Тогда
Возврат ЧисловойЛитерал();
ИначеЕсли _ТекущийТокен.Тип = ТипыТокенов.Строка Тогда
Возврат СтроковойЛитерал();
Иначе
Ошибка("Ожидался литерал, а получен " + _ТекущийТокен.Тип);
КонецЕсли;
КонецФункции
Функция СтроковойЛитерал()
Токен = Потребить(ТипыТокенов.Строка);
Возврат УтилитыПарсера.СтруктураТокена(ТипыТокенов.СтроковыйЛитерал, Токен.Значение);
КонецФункции
Функция ЧисловойЛитерал()
Токен = Потребить(ТипыТокенов.Число);
Возврат УтилитыПарсера.СтруктураТокена(ТипыТокенов.ЧисловойЛитерал, Число(Токен.Значение));
КонецФункции
Функция Потребить(ТипТокена)
Токен = _ТекущийТокен;
Если Токен.Тип = Неопределено Тогда
Ошибка("Неожиданный конец ввода " + ТипТокена);
КонецЕсли;
Если Токен.Тип <> ТипТокена Тогда
Ошибка("Ожидался " + ТипТокена + ", а получен " + Токен.Тип);
КонецЕсли;
_ТекущийТокен = _Токенизатор.СледующийТокен();
Возврат Токен;
КонецФункции
Процедура Ошибка(ТекстОшибки)
ВызватьИсключение ТекстОшибки;
КонецПроцедуры

View File

@ -0,0 +1,40 @@
Перем ДопустимыеСимволы;
Перем ДопустимыеСимволыЦифры;
Процедура ПриСозданииОбъекта()
ДопустимыеСимволы = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZабвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
ДопустимыеСимволыЦифры = "0123456789" + ДопустимыеСимволы;
КонецПроцедуры
Функция Проверить(Знач Строка) Экспорт
Курсор = 1;
Если ЭтоДопустимыйСимвол(УтилитыПарсера.СимволСтроки(Строка, 1)) Тогда
МассивСимволов = Новый Массив;
Пока ЭтоДопустимыйСимвол(УтилитыПарсера.СимволСтроки(Строка, Курсор), Истина)
и Курсор <= СтрДлина(Строка) Цикл
МассивСимволов.Добавить(УтилитыПарсера.СимволСтроки(Строка, Курсор));
Курсор = Курсор + 1;
КонецЦикла;
Результат = СтрСоединить(МассивСимволов);
Возврат Новый Структура("Значение, Размер", Результат, СтрДлина(Результат));
КонецЕсли;
Возврат Неопределено;
КонецФункции
Функция ТипТокена() Экспорт
Возврат ТипыТокенов.Идентификатор;
КонецФункции
Функция ЭтоДопустимыйСимвол(Символ, УчитыватьЦифры = Ложь)
Возврат СтрНайти(
?(УчитыватьЦифры, ДопустимыеСимволыЦифры, ДопустимыеСимволы),
Символ) > 0;
КонецФункции

View File

@ -1,18 +1,25 @@
Процедура ПриСозданииОбъекта()
Перем _Пропускать;
Процедура ПриСозданииОбъекта(Учитывать = Ложь)
_Пропускать = НЕ Учитывать;
КонецПроцедуры
Функция Проверить(Знач Строка) Экспорт
Курсор = 1;
Если УтилитыПарсера.СимволСтроки(Строка, 1) = " " Тогда
Результат = Новый Массив();
Пока УтилитыПарсера.СимволСтроки(Строка, Курсор) = " "
и Курсор <= СтрДлина(Строка) Цикл
Курсор = Курсор + 1;
Результат.Добавить(" ");
КонецЦикла;
Возврат Новый Структура("Значение, Конец", Неопределено, Курсор);
Если _Пропускать Тогда
Возврат Новый Структура("Значение, Размер", Неопределено, Результат.Количество());
Иначе
Возврат Новый Структура("Значение, Размер", СтрСоединить(Результат), Результат.Количество());
КонецЕсли;
КонецЕсли;
Возврат Неопределено;
@ -20,5 +27,5 @@
КонецФункции
Функция ТипТокена() Экспорт
Возврат Неопределено;
Возврат ?(_Пропускать, Неопределено, ТипыТокенов.Пробел);
КонецФункции

View File

@ -0,0 +1,24 @@
Перем _РегулярноеВыражение;
Перем _Тип;
Процедура ПриСозданииОбъекта(РегулярноеВыражение, ТипТокена = Неопределено)
_РегулярноеВыражение = РегулярноеВыражение;
_Тип = ТипТокена;
КонецПроцедуры
Функция Проверить(Знач Строка) Экспорт
Совпадения = _РегулярноеВыражение.НайтиСовпадения(Строка);
Если Совпадения.Количество() > 0 И Совпадения[0].Индекс = 0 Тогда
Возврат Новый Структура("Значение, Размер", Совпадения[0].Значение, Совпадения[0].Длина);
КонецЕсли;
Возврат Неопределено;
КонецФункции
Функция ТипТокена() Экспорт
Возврат _Тип;
КонецФункции

View File

@ -0,0 +1,26 @@
Перем _Символ;
Перем _Тип;
Процедура ПриСозданииОбъекта(Символ, ТипТокена = Неопределено)
_Символ = Символ;
_Тип = ТипТокена;
КонецПроцедуры
Функция Проверить(Знач Строка) Экспорт
ТекСимвол = УтилитыПарсера.СимволСтроки(Строка, 1);
Если ТекСимвол = _Символ Тогда
Возврат Новый Структура("Значение, Размер", ТекСимвол, 1);
КонецЕсли;
Возврат Неопределено;
КонецФункции
Функция ТипТокена() Экспорт
Возврат _Тип;
КонецФункции

View File

@ -1,27 +1,26 @@
Перем СпецификацияТокенРегулярноеВыражение;
Процедура ПриСозданииОбъекта()
Процедура ПриСозданииОбъекта(ЭкранирующийСимвол = """")
СпецификацияТокенРегулярноеВыражение = Новый СпецификацияТокенРегулярноеВыражение(
Новый РегулярноеВыражение(ТекстРегулярногоВыражения(ЭкранирующийСимвол)));
КонецПроцедуры
Функция Проверить(Знач Строка) Экспорт
Курсор = 1;
Если УтилитыПарсера.СимволСтроки(Строка, 1) = """" Тогда
МассивСимволов = Новый Массив;
Курсор = Курсор + 1; // Пропускаем "
Пока УтилитыПарсера.СимволСтроки(Строка, Курсор) <> """"
и Курсор <= СтрДлина(Строка) Цикл
МассивСимволов.Добавить(УтилитыПарсера.СимволСтроки(Строка, Курсор));
Курсор = Курсор + 1;
КонецЦикла;
Возврат Новый Структура("Значение, Конец", СтрСоединить(МассивСимволов), Курсор);
КонецЕсли;
Возврат Неопределено;
Возврат СпецификацияТокенРегулярноеВыражение.Проверить(Строка);
КонецФункции
Функция ТипТокена() Экспорт
Возврат ТипыТокенов.Строка;
КонецФункции
Функция ТекстРегулярногоВыражения(ЭкранирующийСимвол)
Если ЭкранирующийСимвол = """" Тогда
Возврат """(""""|[^""""])*""";
ИначеЕсли ЭкранирующийСимвол = "\" Тогда
Возврат """(\\.|[^""\\])*""";
Иначе
ВызватьИсключение СтрШаблон("Неизвестный экранирующий символ %1", ЭкранирующийСимвол);
КонецЕсли;
КонецФункции

View File

@ -14,7 +14,7 @@
Курсор = Курсор + 1;
КонецЦикла;
Возврат Новый Структура("Значение, Конец", Числа, Курсор);
Возврат Новый Структура("Значение, Размер", Числа, СтрДлина(Числа));
КонецЕсли;

View File

@ -0,0 +1,28 @@
Перем _Значение;
Перем _Тип;
Перем _Начало;
Перем _Размер;
Процедура ПриСозданииОбъекта(Значение, Тип, Начало, Размер)
_Значение = Значение;
_Тип = Тип;
_Начало = Начало;
_Размер = Размер;
КонецПроцедуры
Функция Значение() Экспорт
Возврат _Значение;
КонецФункции
Функция ТипТокена() Экспорт
Возврат _Тип;
КонецФункции
Функция Начало() Экспорт
Возврат _Начало;
КонецФункции
Функция Размер() Экспорт
Возврат _Размер;
КонецФункции

View File

@ -3,23 +3,25 @@
Перем _Курсор;
Перем _Спецификация;
Процедура ПриСозданииОбъекта()
КонецПроцедуры
Процедура ПриСозданииОбъекта(Спецификация)
Процедура Инит(Строка, Спецификация) Экспорт
_Строка = Строка;
_Курсор = 1;
_Спецификация = Спецификация;
КонецПроцедуры
Функция ЕстьЕщеТокены()
Возврат _Курсор < СтрДлина(_Строка);
Процедура Инит(Строка) Экспорт
_Строка = Строка;
_Курсор = 1;
КонецПроцедуры
Функция ЕстьЕщеТокены() Экспорт
Возврат _Курсор <= СтрДлина(_Строка);
КонецФункции
Функция СледующийТокен() Экспорт
Если Не ЕстьЕщеТокены() Тогда
Возврат Неопределено;
КонецЕсли;
@ -34,15 +36,19 @@
Продолжить;
КонецЕсли;
_Курсор = ЗначениеТокена.Конец;
НачалоТокена = _Курсор;
_Курсор = НачалоТокена + ЗначениеТокена.Размер;
Если СпецификацияТокена.ТипТокена() = Неопределено Тогда
Возврат СледующийТокен();
КонецЕсли;
Возврат УтилитыПарсера.СтруктураТокена(СпецификацияТокена.ТипТокена(), ЗначениеТокена.Значение);
Возврат Новый Токен(ЗначениеТокена.Значение, СпецификацияТокена.ТипТокена(), НачалоТокена, ЗначениеТокена.Размер);
КонецЦикла;
Возврат Неопределено;
ВызватьИсключение СтрШаблон("Не найдено токенов в строке %1", Строка);
// Возврат Неопределено;
КонецФункции

View File

@ -2,12 +2,15 @@
Перем Число Экспорт;
Перем Строка Экспорт;
Перем Программа Экспорт;
Перем Идентификатор Экспорт;
Перем Пробел Экспорт;
Перем ЧисловойЛитерал Экспорт;
Перем СтроковыйЛитерал Экспорт;
Число = "Число";
Строка = "Строка";
Программа = "Программа";
Идентификатор = "Идентификатор";
Пробел = "Пробел";
ЧисловойЛитерал = "ЧисловойЛитерал";
СтроковыйЛитерал = "СтроковыйЛитерал";

31
tasks/coverage.os Normal file
View File

@ -0,0 +1,31 @@
#Использовать 1commands
#Использовать fs
#Использовать coverage
СистемнаяИнформация = Новый СистемнаяИнформация;
ЭтоWindows = Найти(НРег(СистемнаяИнформация.ВерсияОС), "windows") > 0;
ФС.ОбеспечитьПустойКаталог("out");
ПутьКСтат = "out/stat.json";
Команда = Новый Команда;
Команда.УстановитьКоманду("oscript");
Если НЕ ЭтоWindows Тогда
Команда.ДобавитьПараметр("-encoding=utf-8");
КонецЕсли;
Команда.ДобавитьПараметр(СтрШаблон("-codestat=%1", ПутьКСтат));
Команда.ДобавитьПараметр("tasks/test.os"); // Файла запуска тестов
Команда.ПоказыватьВыводНемедленно(Истина);
КодВозврата = Команда.Исполнить();
ПроцессорГенерации = Новый ГенераторОтчетаПокрытия();
ПроцессорГенерации.ОтносительныеПути()
.РабочийКаталог("out")
.ИмяФайлаСтатистики()
.GenericCoverage()
.Cobertura()
.Сформировать();
ЗавершитьРаботу(КодВозврата);

1
tasks/oscript.cfg Normal file
View File

@ -0,0 +1 @@
lib.system=../oscript_modules

42
tasks/tests.os Normal file
View File

@ -0,0 +1,42 @@
#Использовать 1testrunner
#Использовать fs
Функция ПрогнатьТесты()
Тестер = Новый Тестер;
Тестер.УстановитьФорматЛогФайла(Тестер.ФорматыЛогФайла().GenericExec);
ПутьКТестам = "tests";
ПутьКОтчетуJUnit = "out";
ФС.ОбеспечитьПустойКаталог(ПутьКОтчетуJUnit);
РезультатТестирования = Тестер.ТестироватьКаталог(
Новый Файл(ПутьКТестам),
Новый Файл(ПутьКОтчетуJUnit)
);
Успешно = РезультатТестирования = 0;
Возврат Успешно;
КонецФункции // ПрогнатьТесты()
// основной код
ТекКаталог = ТекущийКаталог();
Попытка
ТестыПрошли = ПрогнатьТесты();
Исключение
ТестыПрошли = Ложь;
Сообщить(СтрШаблон("Тесты через 1testrunner выполнены неудачно
|%1", ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
КонецПопытки;
УстановитьТекущийКаталог(ТекКаталог);
Если Не ТестыПрошли Тогда
ВызватьИсключение "Тестирование завершилось неудачно!";
Иначе
Сообщить(СтрШаблон("Результат прогона тестов <%1>
|", ТестыПрошли));
КонецЕсли;

218
tests/alltest.os Normal file
View File

@ -0,0 +1,218 @@
#Использовать ".."
#Использовать asserts
&Тест
Процедура Тест_Токенизатор1() Экспорт
// Дано
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенСтрока());
Спека.Добавить(Новый СпецификацияТокенЧисло());
Спека.Добавить(Новый СпецификацияТокенПробелы(Ложь));
Токенизатор = Новый Токенизатор(Спека);
// Когда
Токенизатор.Инит("123 5 ""890""");
// Тогда
Результат = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Результат.Добавить(Токенизатор.СледующийТокен());
КонецЦикла;
Ожидаем.Что(Результат.Количество()).Равно(3);
Ожидаем.Что(Результат[0].Значение()).Равно("123");
Ожидаем.Что(Результат[1].Значение()).Равно("5");
Ожидаем.Что(Результат[2].Значение()).Равно("""890""");
Ожидаем.Что(Результат[0].ТипТокена()).Равно(ТипыТокенов.Число);
Ожидаем.Что(Результат[1].ТипТокена()).Равно(ТипыТокенов.Число);
Ожидаем.Что(Результат[2].ТипТокена()).Равно(ТипыТокенов.Строка);
Ожидаем.Что(Результат[0].Начало()).Равно(1);
Ожидаем.Что(Результат[1].Начало()).Равно(5);
Ожидаем.Что(Результат[2].Начало()).Равно(7);
Ожидаем.Что(Результат[0].Размер()).Равно(3);
Ожидаем.Что(Результат[1].Размер()).Равно(1);
Ожидаем.Что(Результат[2].Размер()).Равно(5);
КонецПроцедуры
&Тест
Процедура Тест_Токенизатор2() Экспорт
// Дано
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенСтрока());
Спека.Добавить(Новый СпецификацияТокенЧисло());
Спека.Добавить(Новый СпецификацияТокенПробелы(Истина));
Токенизатор = Новый Токенизатор(Спека);
// Когда
Токенизатор.Инит("""123"" 5 ""890""");
// Тогда
Результат = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Результат.Добавить(Токенизатор.СледующийТокен());
КонецЦикла;
Ожидаем.Что(Результат.Количество()).Равно(5);
Ожидаем.Что(Результат[0].Значение()).Равно("""123""");
Ожидаем.Что(Результат[2].Значение()).Равно("5");
Ожидаем.Что(Результат[4].Значение()).Равно("""890""");
Ожидаем.Что(Результат[0].ТипТокена()).Равно(ТипыТокенов.Строка);
Ожидаем.Что(Результат[2].ТипТокена()).Равно(ТипыТокенов.Число);
Ожидаем.Что(Результат[4].ТипТокена()).Равно(ТипыТокенов.Строка);
Ожидаем.Что(Результат[0].Начало()).Равно(1);
Ожидаем.Что(Результат[2].Начало()).Равно(7);
Ожидаем.Что(Результат[4].Начало()).Равно(9);
Ожидаем.Что(Результат[0].Размер()).Равно(5);
Ожидаем.Что(Результат[2].Размер()).Равно(1);
Ожидаем.Что(Результат[4].Размер()).Равно(5);
Ожидаем.Что(Результат[1].Значение()).Равно(" ");
Ожидаем.Что(Результат[1].Начало()).Равно(6);
Ожидаем.Что(Результат[1].Размер()).Равно(1);
Ожидаем.Что(Результат[1].ТипТокена()).Равно(ТипыТокенов.Пробел);
Ожидаем.Что(Результат[3].Значение()).Равно(" ");
Ожидаем.Что(Результат[3].Начало()).Равно(8);
Ожидаем.Что(Результат[3].Размер()).Равно(1);
Ожидаем.Что(Результат[3].ТипТокена()).Равно(ТипыТокенов.Пробел);
КонецПроцедуры
&Тест
Процедура Тест_Токенизатор3() Экспорт
// Дано
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенСтрока());
Спека.Добавить(Новый СпецификацияТокенЧисло());
Спека.Добавить(Новый СпецификацияТокенПробелы(Ложь));
Спека.Добавить(Новый СпецификацияТокенСимвол("<", "OPENTAG"));
Спека.Добавить(Новый СпецификацияТокенСимвол(">", "CLOSETAG"));
Спека.Добавить(Новый СпецификацияТокенСимвол("=", "ЕQUAL"));
Спека.Добавить(Новый СпецификацияТокенИдентификатор());
Токенизатор = Новый Токенизатор(Спека);
// Когда
Токенизатор.Инит("<tag name=""1 2 3"">");
// Тогда
Результат = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Результат.Добавить(Токенизатор.СледующийТокен());
КонецЦикла;
Ожидаем.Что(Результат.Количество()).Равно(6);
Ожидаем.Что(Результат[0].Значение()).Равно("<");
Ожидаем.Что(Результат[1].Значение()).Равно("tag");
Ожидаем.Что(Результат[2].Значение()).Равно("name");
Ожидаем.Что(Результат[3].Значение()).Равно("=");
Ожидаем.Что(Результат[4].Значение()).Равно("""1 2 3""");
Ожидаем.Что(Результат[5].Значение()).Равно(">");
Ожидаем.Что(Результат[0].ТипТокена()).Равно("OPENTAG");
КонецПроцедуры
&Тест
Процедура Тест_Токенизатор_регулярка() Экспорт
// Дано
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенРегулярноеВыражение(Новый РегулярноеВыражение("\d+"), "РегекспЧисло"));
Спека.Добавить(Новый СпецификацияТокенРегулярноеВыражение(Новый РегулярноеВыражение("[а-я]+"), "РегекспСтрока"));
Спека.Добавить(Новый СпецификацияТокенСимвол(",", "Запятая"));
Токенизатор = Новый Токенизатор(Спека);
// Когда
Токенизатор.Инит("фб12,34а");
// Тогда
Результат = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Результат.Добавить(Токенизатор.СледующийТокен());
КонецЦикла;
Ожидаем.Что(Результат.Количество()).Равно(5);
Ожидаем.Что(Результат[0].Значение()).Равно("фб");
Ожидаем.Что(Результат[1].Значение()).Равно("12");
Ожидаем.Что(Результат[2].Значение()).Равно(",");
Ожидаем.Что(Результат[3].Значение()).Равно("34");
Ожидаем.Что(Результат[4].Значение()).Равно("а");
Ожидаем.Что(Результат[1].ТипТокена()).Равно("РегекспЧисло");
Ожидаем.Что(Результат[3].ТипТокена()).Равно("РегекспЧисло");
КонецПроцедуры
&Тест
Процедура Тест_Токенизатор_СтрокиСЭкранинованиемКовычкой() Экспорт
// Дано
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенСтрока());
Спека.Добавить(Новый СпецификацияТокенСимвол(",", "Запятая"));
Токенизатор = Новый Токенизатор(Спека);
// Когда
Строка = """1 - """"один"""""",""2 - """"два"""" """;
Токенизатор.Инит(Строка);
// Тогда
Результат = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Результат.Добавить(Токенизатор.СледующийТокен());
КонецЦикла;
Ожидаем.Что(Результат.Количество()).Равно(3);
Ожидаем.Что(Результат[0].Значение()).Равно("""1 - """"один""""""");
Ожидаем.Что(Результат[2].Значение()).Равно("""2 - """"два"""" """);
КонецПроцедуры
&Тест
Процедура Тест_Токенизатор_СтрокиСЭкранинованиемСлешом() Экспорт
// Дано
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенСтрока("\"));
Спека.Добавить(Новый СпецификацияТокенСимвол(",", "Запятая"));
Токенизатор = Новый Токенизатор(Спека);
// Когда
Строка = """1 - \""один\"""",""2 - \""два\"" """;
Токенизатор.Инит(Строка);
// Тогда
Результат = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Результат.Добавить(Токенизатор.СледующийТокен());
КонецЦикла;
Ожидаем.Что(Результат.Количество()).Равно(3);
Ожидаем.Что(Результат[0].Значение()).Равно("""1 - \""один\""""");
Ожидаем.Что(Результат[2].Значение()).Равно("""2 - \""два\"" """);
КонецПроцедуры

View File

@ -1,18 +0,0 @@
#Использовать ".."
#Использовать asserts
Парсер = Новый Парсер();
Парсер.ДобавитьСпецификацию(Новый СпецификацияТокенСтрока());
Парсер.ДобавитьСпецификацию(Новый СпецификацияТокенЧисло());
Парсер.ДобавитьСпецификацию(Новый СпецификацияТокенПробелы());
АСТстрока = Парсер.Распарсить("""абв""");
АСТЧислоИСтрока = Парсер.Распарсить("""абв г""123");
АСТЧисло = Парсер.Распарсить(" 123 ");
а = Сред("123", 0, 1);
в=5;

27
tests/eventlog.os Normal file
View File

@ -0,0 +1,27 @@
#Использовать ".."
#Использовать asserts
#Использовать "features"
Спека = Новый Массив();
Спека.Добавить(Новый СпецификацияТокенПробелы(Истина));
Спека.Добавить(Новый СпецификацияТокенСимвол("{", "Открыть"));
Спека.Добавить(Новый СпецификацияТокенСимвол("}", "Закрыть"));
Спека.Добавить(Новый СпецификацияТокенСимвол(",", "Запятая"));
Спека.Добавить(Новый СпецификацияТокенРегулярноеВыражение(Новый РегулярноеВыражение("(1CV8LOG)|(\(\w+ \d.\d\))"), "Версия"));
Спека.Добавить(Новый СпецификацияТокенРегулярноеВыражение(Новый РегулярноеВыражение("[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$"), "Гуид"));
Спека.Добавить(Новый СпецификацияТокенРегулярноеВыражение(Новый РегулярноеВыражение("[\da-z]+"), "Идентификатор"));
Спека.Добавить(Новый СпецификацияТокенСтрока());
Спека.Добавить(Новый СпецификацияТокенЧисло());
Спека.Добавить(Новый СпецификацияТокенСимвол(Символы.ПС, "ПереносСтроки"));
Токенизатор = Новый Токенизатор(Спека);
ЧтениеТекста = Новый ЧтениеТекста("tests/features/small.lgp");
Текст = ЧтениеТекста.Прочитать();
ЧтениеТекста.Закрыть();
Токенизатор.Инит(Текст);
Скобарь = Новый ПарсерСкобки(Токенизатор);
Результат = Скобарь.Распарсить();
Сообщить(Результат.Количество());

14
tests/features/small.lgp Normal file
View File

@ -0,0 +1,14 @@
1CV8LOG(ver 2.0)
758d6f0a-476f-468b-80ac-48773092049c
{20221110000049,N,
{2444a6a24da10,3d},1,1,1,1803214,81,I,"Первое событие",599,
{"U"},"Представление данных",1,1,9,3,0,
{0}
},
{20221110000049,U,
{2444a6a24da10,3d},1,1,1,1803214,81,E,"Второе ""событие""
многострочное ",599,
{"U"},"Представление данных2",1,1,9,3,0,
{2,1,31,2,31}
}

View File

@ -0,0 +1,42 @@
Перем Токенизатор;
Перем ПрошлиЗаголовок;
Процедура ПриСозданииОбъекта(Лексер)
Токенизатор = Лексер;
ПрошлиЗаголовок = Ложь;
КонецПроцедуры
Функция Распарсить() Экспорт
ТекущийМассив = Новый Массив();
Пока Токенизатор.ЕстьЕщеТокены() Цикл
Токен = Токенизатор.СледующийТокен();
Если ПрошлиЗаголовок = Ложь И Не Токен.ТипТокена() = "Открыть" Тогда
Продолжить;
КонецЕсли;
ПрошлиЗаголовок = Истина;
Если Токен.ТипТокена() = "Открыть" Тогда
ТекущийМассив.Добавить(Распарсить());
Продолжить;
КонецЕсли;
Если Токен.ТипТокена() = "Идентификатор"
ИЛИ Токен.ТипТокена() = "Число"
ИЛИ Токен.ТипТокена() = "Строка" Тогда
ТекущийМассив.Добавить(Токен.Значение());
КонецЕсли;
Если Токен.ТипТокена() = "Закрыть" Тогда
Возврат ТекущийМассив;
КонецЕсли;
КонецЦикла;
Возврат ТекущийМассив;
КонецФункции