Initial commit

This commit is contained in:
IRBorisov 2024-06-07 20:09:31 +03:00
commit 2bd3bb3f12
32 changed files with 2295 additions and 0 deletions

42
VBAMake.txt Normal file
View File

@ -0,0 +1,42 @@
# == Properties Section ==
# configuration properties
# use .ini format to define properties
# mandatory properties: name, artifact_home, source_home
id = Concept-Mining
name = Концепт-Майнинг
description = Модуль извлечения (парсинга) данных из текстов
artifact_home = Концепт-Майнинг
source_home = Concept-Mining
install_home = \\fs1.concept.ru\projects\10 Автоматизация деятельности\01 Высокие технологии\Концепт-Майнинг
%%
# === Build section ===
# Available commands:
# build LOCAL_MANIFEST
# copy LOCAL_SOURCE -> [LOCAL_ARTIFACT]
# save_as LOCAL_ARTIFACT -> LOCAL_ARTIFACT
# run LOCAL_SOURCE.bat
copy test
copy distr\models\ActionVerbs.txt -> models\ActionVerbs.txt
build script\addinManifest.txt
build script\databaseManifest.txt
save_as !Майнинг.xlsm -> 55 Майнинг.xltm
%%
# === Install section ==
# Available commands:
# install LOCAL_ARTIFACT -> [INSTALL_PATH]
# add_template LOCAL_ARTIFACT -> [LOCAL_TEMPLATE]
# run LOCAL_ARTIFACT.bat <- [PARAMETERS]
# run APPLICATION <- [PARAMETERS]
install Надстройка\Parsers.dotm -> Надстройка\Parsers.dotm
install !Майнинг.xlsm
install 55 Майнинг.xltm
install Надстройка\Parsers.dotm -> \\fs1.concept.ru\Exchange\ConceptDistr\data\Add-ins\Word\Parsers.dotm
install models\ActionVerbs.txt -> \\fs1.concept.ru\Exchange\ConceptDistr\models\ActionVerbs.txt
add_template 55 Майнинг.xltm

1
VERSION Normal file
View File

@ -0,0 +1 @@
1.4.0

View File

@ -0,0 +1,463 @@
аккредитирует
анализирует
аннулирует
апробирует
вводит
ведет
взаимодействует
владеет
внедряет
вносит
возглавляет
возмещает
возобновляет
вступает
входит
выбирает
выдает
выплачивает
выполняет
выражает
выступает
выявляет
голосует
готовит
дает
действует
делегирует
доводит
доставляет
заключает
закрепляет
закрывает
заполняет
запрашивает
запрещает
заслушивает
защищает
заявляет
знакомит
знакомится
избирает
издает
изменяет
изучает
изымает
имеет
инициирует
информирует
исполняет
использует
истребует
комплектует
консультирует
контролирует
координирует
награждает
назначает
налагает
направляет
несет
обеспечивает
обжалует
обладает
обнародует
обобщает
оборудует
образует
обращается
обязывает
ограничивает
одобряет
оказывает
открывает
оповещает
определяет
организовывает
организует
освещает
освобождает
осуществляет
отвечает
отклоняет
открывает
отменяет
отрешает
отстраняет
отчитывается
оформляет
оценивает
передает
переоформляет
перечисляет
планирует
подготавливает
поддерживает
подписывает
получает
пользуется
поощряет
посещает
предлагает
предоставляет
председательствует
представляет
предъявляет
прекращает
привлекает
приглашает
признает
применяет
принимает
приобретает
приостанавливает
присваивает
проверяет
проводит
прогнозирует
продлевает
производит
публикует
развивает
размещает
разрабатывает
разрешает
разъясняет
распоряжается
распределяет
распускает
рассматривает
рассчитывает
расторгает
реализовывает
реализует
регистрирует
регулирует
решает
руководит
санкционирует
совершает
совершенствует
согласовывает
согласует
содействует
содержит
создает
созывает
составляет
способствует
требует
уведомляет
удостоверяет
уполномочивает
управляет
устанавливает
утверждает
участвует
учреждает
формирует
является
аккредитовать
анализировать
аннулировать
апробировать
вводить
вести
взаимодействовать
владеть
внедрять
вносить
возглавлять
возмещать
возобновлять
вступать
входить
выбирать
выдавать
выплачивать
выполнять
выражать
выступать
выявлять
голосовать
готовить
давать
действовать
делегировать
доводить
доставлять
заключать
закреплять
закрывать
заполнять
запрашивать
запрещать
заслушивать
защищать
заявлять
знакомить
знакомиться
избирать
издавать
изменять
изучать
изымать
иметь
инициировать
информировать
исполнять
использовать
истребовать
комплектовать
консультировать
контролировать
координировать
награждать
назначать
налагать
направлять
нести
обеспечивать
обжаловать
обладать
обнародовать
обобщать
оборудовать
образовывать
обращаться
обязывать
ограничивать
одобрять
оказывать
открывать
оповещать
определять
организовывать
организовать
освещать
освобождать
осуществлять
отвечать
отклонять
открывать
отменять
отрешать
отстранять
отчитываться
оформлять
оценивать
передать
переоформлять
перечислять
планировать
подготавливать
поддерживать
подписывать
получать
пользоваться
поощрять
посещать
предлагать
предоставлять
председательствовать
представлять
предъявлять
прекращать
привлекать
приглашать
признать
применять
принимать
приобретать
приостанавливать
присваивать
проверять
проводить
прогнозировать
продлевать
производить
публиковать
развивать
размещать
разрабатывать
разрешать
разъяснять
распоряжаться
распределять
распускать
рассматривать
рассчитывать
расторгать
реализовывать
реализовать
регистрировать
регулировать
решать
руководить
санкционировать
совершать
совершенствовать
согласовывать
согласовать
содействовать
содержать
создавать
созывать
составлять
способствовать
требовать
уведомлять
удостоверять
уполномочивать
управлять
устанавливать
утверждать
участвовать
учреждать
формировать
являться
аккредитация
анализирование
аннулирование
апробирование
введение
ведение
взаимодействие
владение
внедрение
внесение
возглавление
возмещение
возобновление
вступление
вхождение
выбирание
выдавание
выплачивание
выполнение
выражение
выступление
выявление
голосование
дача
действие
делегирование
доведение
доставление
заключение
закрепление
закрывание
заполнение
запрашивание
запрещение
заслушивание
защита
заявление
знакомство
ознакомление
избирание
издание
изменение
изучение
изъятие
имение
иницирование
информирование
исполнение
использование
требование
комплектование
консультирование
контролирование
координирование
награждение
назначение
налагание
направление
несение
обеспечение
обжалование
обладание
обнародование
обобщение
оборудование
обращение
ограничение
одобрение
оказание
открывание
оповещение
определение
освещение
освобождение
осуществление
отвечание
отклонение
открывание
отрешение
отстранение
оформление
передача
переоформление
перечисление
планирование
поддерживание
подписывание
получение
пользование
поощрение
посещение
предложение
предоставление
председательствование
представление
предъявление
прекращение
привлечение
приглашение
признание
применение
приобретение
приостановление
присваивание
проверка
проведение
прогнозирование
продление
производство
публикование
развитие
размещение
разрабатывание
разрешение
разъяснение
распоряжение
распределение
распускание
рассмотрение
расторжение
реализация
регистрирование
регулирование
решение
руководство
санкционирование
совершение
совершенствование
согласование
содействие
содержание
создание
составление
способствование
требование
уведомление
удостоверение
уполномочивание
управление
установление
утверждение
участие
учреждение
формирование
явление

102
script/addinManifest.txt Normal file
View File

@ -0,0 +1,102 @@
# == Properties Section ==
# configuration properties
# use .ini format to define properties
# mandatory properties: name, artifact
name = Parsers.dotm
artifact = Надстройка\Parsers.dotm
%%
# === Imports Section ===
# Hierarchy of folders and files
# Use Tabulator to mark next level in hierarchy
# All folders are nested into SharedHome path
api
ex_Python.bas
ex_WinAPI.bas
API_Python.cls
API_Ribbon.cls
API_XLWrapper.cls
API_UserInteraction.cls
word
ex_Word.bas
parsers
ParserDeclarations.bas
z_ParserRegex.bas
PC_ParsedData.cls
PC_Fragment.cls
ExtractionOptions.cls
PC_Tools.cls
DetectorClassifier.cls
DetectorListWords.cls
DetectorRegex.cls
DetectorMorpho.cls
ParserDate.cls
ParserNPA.cls
PC_InfoNPA.cls
utility
ex_VBA.bas
ex_Regex.bas
ex_DataPreparation.bas
API_Config.cls
API_JSON.cls
API_Timer.cls
ui
CSE_ProgressBar.frm
dev
DevTester.bas
%%
# === Source Code Section ==
# Hierarchy of folders and files
# Use Tabulator to mark next level in hierarchy
# All folders are nested into SourceHome path
src
addin
DevHelper.bas
Declarations.bas
Main.bas
MainImpl.bas
z_UIRibbon.bas
z_UIMessages.bas
UIState.cls
IteratorDetected.cls
%%
# ===== UI Section =======
# Pairs of path to UI elements, use " -> " delimiter
# First component is a path relative to SourceHome\ui folders
# Second component is internal path inside project file
addin\.rels -> _rels\.rels
addin\customUI.xml -> customUI\customUI.xml
%%
# === References Section ===
# List dependencies in one of the formats
# global : GLOBAL_NAME
# guid : {REGISTERED_GUID}
# file : PATH_TO_LIBRARY
global : VBScript_RegExp_55
global : Scripting
global : Shell32
global : MSForms
global : ADODB
global : Excel

View File

@ -0,0 +1,82 @@
# == Properties Section ==
# configuration properties
# use .ini format to define properties
# mandatory properties: name, artifact
name = !Майнинг.xlsm
artifact = !Майнинг.xlsm
%%
# === Imports Section ===
# Hierarchy of folders and files
# Use Tabulator to mark next level in hierarchy
# All folders are nested into SharedHome path
api
ex_WinAPI.bas
API_WordWrapper.cls
API_XLWrapper.cls
API_UserInteraction.cls
parsers
ParserDeclarations.bas
ExtractionOptions.cls
utility
ex_VBA.bas
ex_DataPreparation.bas
ex_Version.bas
API_DistrManifest.cls
API_JSON.cls
API_Timer.cls
ui
CSE_ProgressBar.frm
dev
DevTester.bas
%%
# === Source Code Section ==
# Hierarchy of folders and files
# Use Tabulator to mark next level in hierarchy
# All folders are nested into SourceHome path
src
database
ImportDlg.frm
DevHelper.bas
Declarations.bas
DataAccess.bas
Main.bas
MainImpl.bas
ManualSubs.bas
z_UIRibbon.bas
z_UIMessages.bas
test
s_WordInteractions.cls
%%
# ===== UI Section =======
# Pairs of path to UI elements, use " -> " delimiter
# First component is a path relative to SourceHome\ui folders
# Second component is internal path inside project file
database\.rels -> _rels\.rels
database\customUI.xml -> customUI\customUI.xml
%%
# === References Section ===
# List dependencies in one of the formats
# global : GLOBAL_NAME
# guid : {REGISTERED_GUID}
# file : PATH_TO_LIBRARY
global : Word
global : Shell32
global : Scripting
global : MSForms

Binary file not shown.

BIN
skeleton/Parsers.dotm Normal file

Binary file not shown.

View File

@ -0,0 +1,63 @@
Attribute VB_Name = "Declarations"
Option Private Module
Option Explicit
Public Const MAX_FIND_LEN = 250
Public Const TEMP_FILE_NAME = "conceptParsers"
' Markup color
Public Enum TColor
[_First] = 1
T_COLOR_YELLOW = 1 ' = 7
T_COLOR_GREEN = 2 ' = 4
T_COLOR_TEAL = 3 ' = 10
T_COLOR_GREY = 4 ' = 15
T_COLOR_BLUE = 5 ' = 9
[_Last] = 5
End Enum
' _E_ - export
Public Enum ExportStruct
[_First] = 1
S_E_ID = 1
S_E_START = 2
S_E_FINISH = 3
S_E_TYPE = 4
S_E_TEXT = 5
S_E_DATA = 6
[_Last] = 6
End Enum
Public Function ColorToStr(iColor As TColor) As String
Select Case iColor
Case T_COLOR_YELLOW: ColorToStr = "Æåëòûé"
Case T_COLOR_GREEN: ColorToStr = "Çåëåíûé"
Case T_COLOR_TEAL: ColorToStr = "Ìîðñêîé"
Case T_COLOR_GREY: ColorToStr = "Ñåðûé"
Case T_COLOR_BLUE: ColorToStr = "Ñèíèé"
End Select
End Function
Public Function ColorToColorIndex(iColor As TColor) As Integer
Select Case iColor
Case T_COLOR_YELLOW: ColorToColorIndex = WdColorIndex.wdYellow
Case T_COLOR_GREEN: ColorToColorIndex = WdColorIndex.wdBrightGreen
Case T_COLOR_TEAL: ColorToColorIndex = WdColorIndex.wdTurquoise
Case T_COLOR_GREY: ColorToColorIndex = WdColorIndex.wdGray25
Case T_COLOR_BLUE: ColorToColorIndex = WdColorIndex.wdBlue
End Select
End Function
Public Function PTools() As PC_Tools
Static s_Parsers As PC_Tools
If s_Parsers Is Nothing Then
Set s_Parsers = New PC_Tools
End If
Set PTools = s_Parsers
End Function

20
src/addin/DevHelper.bas Normal file
View File

@ -0,0 +1,20 @@
Attribute VB_Name = "DevHelper"
Option Explicit
Public Function Dev_PrepareSkeleton()
Call ThisDocument.Range.Delete
End Function
Public Sub Dev_ManualRunTest()
Dim sSuite$: sSuite = "s_Database"
Dim sTest$: sTest = "t_RenameLawFile"
Dim sMsg$: sMsg = Dev_RunTestDebug(sSuite, sTest)
Debug.Print sMsg
Call MsgBox(sMsg)
End Sub
Public Function Dev_GetTestSuite(sName$) As Object
Select Case sName
' Case "s_ActiveStateExporter": Set Dev_GetTestSuite = New s_ActiveStateExporter
End Select
End Function

View File

@ -0,0 +1,158 @@
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "IteratorDetected"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
' Èòåðàòîð íà îñíîâå ìåõàíèçìà äåòåêöèè âõîæäåíèé
Option Explicit
Private Const NO_CURRENT_ID = -1
Private selection_ As Word.Range
Private detector_ As Object
Private start_ As Long
Private data_ As PC_ParsedData
Private currentID_ As Long
Public Function Init(theDoc As Word.Document, iDetector As Object, Optional nStart& = 0)
Set selection_ = theDoc.Range(nStart, nStart)
Set detector_ = iDetector
start_ = selection_.Paragraphs.First.Range.Start
Dim sText$: sText = selection_.Paragraphs.First.Range.Text
Set data_ = detector_.ExtractFragments(sText)
currentID_ = IIf(data_.Count = 0, 0, NO_CURRENT_ID)
End Function
Public Function Range() As Word.Range
Set Range = selection_
End Function
Public Function Fragment() As PC_Fragment
If currentID_ <> NO_CURRENT_ID Then _
Set Fragment = data_.data_.Item(currentID_)
End Function
Public Function MoveNext() As Word.Range
If currentID_ = NO_CURRENT_ID Then
If Not InitNext Then _
Exit Function
ElseIf currentID_ = data_.Count Then
If Not NextChunk Then _
Exit Function
currentID_ = 1
Else
currentID_ = currentID_ + 1
End If
Set selection_ = RangeForFragment(data_.data_.Item(currentID_))
Set MoveNext = selection_
End Function
Public Function MovePrev() As Word.Range
If currentID_ = NO_CURRENT_ID Then
If Not InitPrev Then _
Exit Function
ElseIf currentID_ <= 1 Then
If Not PrevChunk Then _
Exit Function
currentID_ = data_.Count
Else
currentID_ = currentID_ - 1
End If
Set selection_ = RangeForFragment(data_.data_.Item(currentID_))
Set MovePrev = selection_
End Function
' ======
Private Function RangeForFragment(iFragment As PC_Fragment) As Word.Range
Dim iRange As Word.Range: Set iRange = selection_.Document.Range(start_, start_)
Call iRange.MoveStart(wdCharacter, iFragment.start_)
Call iRange.Collapse(wdCollapseStart)
Call iRange.MoveEnd(wdCharacter, iFragment.end_ - iFragment.start_)
Set RangeForFragment = iRange
End Function
Private Function InitNext() As Boolean
Dim nTarget&: nTarget = selection_.End
Dim iRange As Word.Range
Dim nFragment&
For nFragment = 1 To data_.Count Step 1
Set iRange = RangeForFragment(data_.data_.Item(nFragment))
If iRange.Start >= nTarget Then
InitNext = True
currentID_ = nFragment
Exit Function
End If
Next nFragment
If Not NextChunk Then _
Exit Function
InitNext = True
currentID_ = 1
End Function
Private Function InitPrev() As Boolean
Dim nTarget&: nTarget = selection_.Start
Dim iRange As Word.Range
Dim nFragment&
For nFragment = data_.Count To 1 Step -1
Set iRange = RangeForFragment(data_.data_.Item(nFragment))
If iRange.End <= nTarget Then
InitPrev = True
currentID_ = nFragment
Exit Function
End If
Next nFragment
If Not PrevChunk Then _
Exit Function
InitPrev = True
currentID_ = data_.Count
End Function
Private Function NextChunk() As Boolean
Dim iRange As Word.Range: Set iRange = selection_.Document.Range(start_, start_)
Dim oldStart&
Do
oldStart = iRange.Start
Call iRange.Move(wdParagraph, 1)
If iRange.Start = oldStart Or iRange.Start + 1 >= selection_.Document.Range.End Then
NextChunk = False
Exit Function
End If
Dim sText$: sText = iRange.Paragraphs.First.Range.Text
Dim iData As PC_ParsedData: Set iData = detector_.ExtractFragments(sText)
If Not iData.IsEmpty Then
NextChunk = True
start_ = iRange.Start
Set data_ = iData
Exit Function
End If
Loop
End Function
Private Function PrevChunk() As Boolean
Dim iRange As Word.Range: Set iRange = selection_.Document.Range(start_, start_)
Do
If iRange.Start = 0 Then
PrevChunk = False
Exit Function
End If
Call iRange.Move(wdParagraph, -1)
Dim sText$: sText = iRange.Paragraphs.First.Range.Text
Dim iData As PC_ParsedData: Set iData = detector_.ExtractFragments(sText)
If Not iData.IsEmpty Then
PrevChunk = True
start_ = iRange.Start
Set data_ = iData
Exit Function
End If
Loop
End Function

178
src/addin/Main.bas Normal file
View File

@ -0,0 +1,178 @@
Attribute VB_Name = "Main"
Option Explicit
Public Function ExportAllData(iParamData() As String) As Variant
Dim oData As New Collection
Dim params As New ExtractionOptions: Call params.FromFlatData(iParamData)
Dim iDoc As Word.Document: Set iDoc = Word.ActiveDocument
Dim oItem As Collection
On Error GoTo RETURN_EMPTY
Dim iDetector As Object: Set iDetector = PTools().Detector(params.detector_, params.param_)
Dim oIterator As New IteratorDetected: Call oIterator.Init(iDoc, iDetector)
Do While Not oIterator.MoveNext Is Nothing
Set oItem = New Collection
Call oItem.Add(oIterator.Range.Start)
Call oItem.Add(oIterator.Range.End)
Call oItem.Add(IIf(oIterator.Fragment.type_ <> 0, oIterator.Fragment.type_, params.loadCategory_))
Call oItem.Add(SubstituteWhitespace(oIterator.Range.Text))
Call oData.Add(oItem)
Loop
On Error GoTo 0
RETURN_EMPTY:
ExportAllData = ConverToFlat2D(oData)
End Function
Public Sub RunNextFragment()
Dim rSelection As Word.Range: Set rSelection = Word.Selection.Range
Dim iDetector As Object: Set iDetector = PTools().Detector(GetUIState.detector_, GetUIState.detectionParam_)
Dim oIterator As New IteratorDetected: Call oIterator.Init(rSelection.Document, iDetector, rSelection.End)
If Not oIterator.MoveNext Is Nothing Then
Call oIterator.Range.Select
Else
Call VBA.Beep
End If
End Sub
Public Sub RunPrevFragment()
Dim rSelection As Word.Range: Set rSelection = Word.Selection.Range
Dim iDetector As Object: Set iDetector = PTools().Detector(GetUIState.detector_, GetUIState.detectionParam_)
Dim oIterator As New IteratorDetected: Call oIterator.Init(rSelection.Document, iDetector, rSelection.Start)
If Not oIterator.MovePrev Is Nothing Then
Call oIterator.Range.Select
Else
Call VBA.Beep
End If
End Sub
Public Sub RunMarkWord()
Dim iDoc As Word.Document: Set iDoc = Word.ActiveDocument
Dim nCount&: nCount = MarkAllDetected(iDoc, GetUIState.detector_, GetUIState.color_, GetUIState.detectionParam_)
Call iDoc.Application.ScreenRefresh
Call UserInteraction.ShowMessage(IM_MARKDOWN_COMPLETE, nCount)
End Sub
Public Sub RunMarkParagraph()
Dim iDoc As Word.Document: Set iDoc = Word.ActiveDocument
Dim nCount&: nCount = MarkAllParagraphs(iDoc, GetUIState.detector_, GetUIState.color_, GetUIState.detectionParam_)
Call iDoc.Application.ScreenRefresh
Call UserInteraction.ShowMessage(IM_MARKDOWN_COMPLETE, nCount)
End Sub
Public Sub RunBrowseFile()
Dim sFile$: sFile = UserInteraction.PromptFileFilter(ActiveDocument.Path & "\", "All files", "*.*")
If sFile = vbNullString Then _
Exit Sub
GetUIState.detectionParam_ = sFile
GetUIState.ribbon_.Value.Invalidate
End Sub
Public Sub RunMorphoParse()
Dim sText$: sText = EnsureSelectedText()
If sText = vbNullString Then _
Exit Sub
Dim sTags$: sTags = MorphoParse(sText)
Call UserInteraction.ShowMessage(IM_PARSE_MORPHO, sTags)
End Sub
Public Sub RunContextInfo()
Dim sText$: sText = EnsureSelectedText()
If sText = vbNullString Then _
Exit Sub
Dim iDetector As Object: Set iDetector = PTools().Detector(GetUIState.detector_, GetUIState.detectionParam_)
If Not iDetector.Test(sText) Then
Call UserInteraction.ShowMessage(IM_TEST_FAILED, DetectorToStr(GetUIState.detector_))
Exit Sub
End If
Dim iParser As Object: Set iParser = PTools().Parser(GetUIState.detector_, GetUIState.detectionParam_)
If iParser Is Nothing Then
Call UserInteraction.ShowMessage(IM_NO_PARSER_DATA, DetectorToStr(GetUIState.detector_))
Exit Sub
End If
If Not iParser.Parse(sText) Then
Call UserInteraction.ShowMessage(IM_NO_PARSER_DATA, DetectorToStr(GetUIState.detector_))
Exit Sub
End If
Call UserInteraction.ShowMessage(IM_PARSED_DESCRIPTION, sText, DetectorToStr(GetUIState.detector_), iParser.GetDataDescription())
End Sub
Public Sub RunTransformSingle()
Dim rSelection As Word.Range: Set rSelection = WordAdjustRange(Word.Selection.Range)
Call rSelection.MoveEndWhile(" ", -1)
Dim sText$: sText = VBA.Trim(rSelection.Text)
If sText = vbNullString Then
Call UserInteraction.ShowMessage(EM_SELECTION_EMPTY)
Exit Sub
End If
Dim iDetector As Object: Set iDetector = PTools().Detector(GetUIState.detector_, GetUIState.detectionParam_)
If Not iDetector.Test(sText) Then
Call UserInteraction.ShowMessage(IM_TEST_FAILED, DetectorToStr(GetUIState.detector_))
Exit Sub
End If
Dim iParser As Object: Set iParser = PTools().Parser(GetUIState.detector_, GetUIState.detectionParam_)
If iParser Is Nothing Then _
Exit Sub
Dim sNewText$: sNewText = iParser.Transform(sText, GetUIState.transformParam_)
If sText <> sNewText Then _
rSelection.Text = sNewText
Call rSelection.Select
End Sub
Public Sub RunTransformAll()
Dim iDoc As Word.Document: Set iDoc = Word.ActiveDocument
Dim nCount&: nCount = TransformAll(iDoc, GetUIState.GetOptions)
Call UserInteraction.ShowMessage(IM_TRANSFORM_COMPLETE, nCount)
End Sub
Public Sub RunExportRanges()
Dim iDoc As Word.Document: Set iDoc = Word.ActiveDocument
Dim xlApp As New API_XLWrapper
Dim outWB As Excel.Workbook: Set outWB = xlApp.NewDocument
Call xlApp.PauseUI
Call OutputRanges(iDoc, outWB.Sheets(1), GetUIState.GetOptions)
Call xlApp.ResumeUI
Call UserInteraction.ShowMessage(IM_EXPORT_COMPLETE)
End Sub
Public Sub RunExportAll()
Dim iDoc As Word.Document: Set iDoc = Word.ActiveDocument
Dim xlApp As New API_XLWrapper
Dim outWB As Excel.Workbook: Set outWB = xlApp.NewDocument
Call xlApp.PauseUI
Call OutputAllData(iDoc, outWB.Sheets(1), GetUIState.GetOptions)
Call xlApp.ResumeUI
Call UserInteraction.ShowMessage(IM_EXPORT_COMPLETE)
End Sub
Public Sub RunHelp()
MsgBox "TODO"
End Sub
' ======
Private Function EnsureSelectedText() As String
Dim rSelection As Word.Range: Set rSelection = WordAdjustRange(Word.Selection.Range)
Dim sText$: sText = VBA.Trim(rSelection.Text)
If sText = vbNullString Then _
Call UserInteraction.ShowMessage(EM_SELECTION_EMPTY)
EnsureSelectedText = sText
End Function

174
src/addin/MainImpl.bas Normal file
View File

@ -0,0 +1,174 @@
Attribute VB_Name = "MainImpl"
Option Explicit
Public Function MarkAllDetected(iDoc As Word.Document, nDetector As TDetector, iColor As TColor, sParam$) As Long
Dim nColor&: nColor = ColorToColorIndex(iColor)
Dim iDetector As Object: Set iDetector = PTools().Detector(nDetector, sParam)
Dim oIterator As New IteratorDetected: Call oIterator.Init(iDoc, iDetector)
Dim iRange As Word.Range
Dim fragmentColor&
Dim nCount&: nCount = 0
Do
Set iRange = oIterator.MoveNext
If iRange Is Nothing Then _
Exit Do
Dim nType&: nType = oIterator.Fragment.type_
fragmentColor = IIf(nType = 0, 0, ColorToColorIndex(TColor.[_First] + ((nType - 1) Mod TColor.[_Last])))
If nCount = 0 Then
Dim oldColor&: oldColor = iRange.HighlightColorIndex
If oldColor = nColor Or (oldColor = fragmentColor And fragmentColor <> 0) Then _
nColor = wdAuto
End If
If nColor <> wdAuto And fragmentColor <> 0 Then _
nColor = fragmentColor
iRange.HighlightColorIndex = nColor
nCount = nCount + 1
Loop
MarkAllDetected = nCount
End Function
Public Function MarkAllParagraphs(iDoc As Word.Document, nDetector As TDetector, iColor As TColor, sParam$) As Long
Dim nColor&: nColor = ColorToColorIndex(iColor)
Dim iDetector As Object: Set iDetector = PTools().Detector(nDetector, sParam)
Dim oIterator As New IteratorDetected: Call oIterator.Init(iDoc, iDetector)
Dim iRange As Word.Range
Dim nCount&: nCount = 0
Dim oldStart&: oldStart = -1
Do
Set iRange = oIterator.MoveNext
If iRange Is Nothing Then _
Exit Do
If nCount = 0 And iRange.HighlightColorIndex = nColor Then _
nColor = wdAuto
iRange.Paragraphs.First.Range.HighlightColorIndex = nColor
If oldStart <> iRange.Start Then
oldStart = iRange.Start
nCount = nCount + 1
End If
Loop
MarkAllParagraphs = nCount
End Function
Public Function MorphoParse(sText$) As String
MorphoParse = AccessPython.CallFunction(PY_MODULE_TEXT, "parse", Array(sText, ""))
End Function
Public Function ConverToFlat2D(oData As Collection) As Variant
Dim iData() As Variant
If oData.Count = 0 Then
ConverToFlat2D = iData
Exit Function
End If
ReDim iData(0 To oData.Count - 1, 0 To oData.Item(1).Count - 1)
Dim nRow&: nRow = 0
Dim oItem As Object
Dim vElement As Variant
For Each oItem In oData
Dim nCol&: nCol = 0
For Each vElement In oItem
iData(nRow, nCol) = vElement
nCol = nCol + 1
Next vElement
nRow = nRow + 1
Next oItem
ConverToFlat2D = iData
End Function
Public Function TransformAll(iDoc As Word.Document, iOptions As ExtractionOptions) As Long
Dim iParser As Object: Set iParser = PTools().Parser(iOptions.detector_, iOptions.param_)
If iParser Is Nothing Then _
Exit Function
Dim iDetector As Object: Set iDetector = PTools().Detector(iOptions.detector_, iOptions.param_)
Dim oIterator As New IteratorDetected: Call oIterator.Init(iDoc, iDetector, iDoc.Range.End - 1)
Dim nCount&: nCount = 0
Do While Not oIterator.MovePrev Is Nothing
Dim sText$: sText = oIterator.Range.Text
Dim sNewText$: sNewText = iParser.Transform(sText, iOptions.transform_)
If sText <> sNewText Then
oIterator.Range.Text = sNewText
Call oIterator.Init(iDoc, iDetector, oIterator.Range.Start)
nCount = nCount + 1
End If
Loop
TransformAll = nCount
End Function
Public Function OutputRanges(iSource As Word.Document, wsOut As Excel.Worksheet, iOptions As ExtractionOptions)
Dim iDetector As Object: Set iDetector = PTools().Detector(iOptions.detector_, iOptions.param_)
Dim oIterator As New IteratorDetected: Call oIterator.Init(iSource, iDetector)
With wsOut
.Cells(1, S_E_ID) = "ID"
.Cells(1, S_E_START) = "Íà÷àëî"
.Cells(1, S_E_FINISH) = "Êîíåö"
.Cells(1, S_E_TYPE) = "Òèï"
End With
Dim nRow&: nRow = 2
Do While Not oIterator.MoveNext Is Nothing
With wsOut
.Cells(nRow, S_E_ID) = nRow - 1
.Cells(nRow, S_E_START) = oIterator.Range.Start
.Cells(nRow, S_E_FINISH) = oIterator.Range.End
.Cells(nRow, S_E_TYPE) = IIf(oIterator.Fragment.type_ = 0, iOptions.loadCategory_, oIterator.Fragment.type_)
End With
nRow = nRow + 1
Loop
End Function
Public Function OutputAllData(iSource As Word.Document, wsOut As Excel.Worksheet, iOptions As ExtractionOptions)
Dim iDetector As Object: Set iDetector = PTools().Detector(iOptions.detector_, iOptions.param_)
Dim iParser As Object: Set iParser = PTools().Parser(iOptions.detector_, iOptions.param_)
Dim oIterator As New IteratorDetected: Call oIterator.Init(iSource, iDetector)
With wsOut
.Cells(1, S_E_ID) = "ID"
.Cells(1, S_E_START) = "Íà÷àëî"
.Cells(1, S_E_FINISH) = "Êîíåö"
.Cells(1, S_E_TYPE) = "Òèï"
.Cells(1, S_E_TEXT) = "Òåêñò"
End With
Dim nRow&: nRow = 2
Dim iData As Collection
Do While Not oIterator.MoveNext Is Nothing
Dim sText$: sText = oIterator.Range.Text
With wsOut
.Cells(nRow, 1) = nRow - 1
.Cells(nRow, 2) = oIterator.Range.Start
.Cells(nRow, 3) = oIterator.Range.End
.Cells(nRow, 4) = IIf(oIterator.Fragment.type_ = 0, iOptions.loadCategory_, oIterator.Fragment.type_)
.Cells(nRow, 5) = sText
End With
If iParser Is Nothing Then _
GoTo NEXT_ROW
If Not iParser.Parse(sText) Then _
GoTo NEXT_ROW
Set iData = iParser.GetData()
If iData.Count = 0 Then _
GoTo NEXT_ROW
Dim nCol&: nCol = S_E_DATA
Dim vItem As Variant
For Each vItem In iData
wsOut.Cells(nRow, nCol) = vItem
nCol = nCol + 1
Next vItem
If nRow <> 2 Then _
GoTo NEXT_ROW
Dim iHeader As Scripting.Dictionary: Set iHeader = iParser.GetDataDescription()
nCol = S_E_DATA
For Each vItem In iHeader.Keys
wsOut.Cells(1, nCol) = vItem
nCol = nCol + 1
Next vItem
NEXT_ROW:
nRow = nRow + 1
Loop
End Function

29
src/addin/ManualSubs.bas Normal file
View File

@ -0,0 +1,29 @@
Attribute VB_Name = "ManualSubs"
Option Explicit
'Public Function P_GetNPAFromActive() As Long()
' Dim frags As New PC_ParsedData
' Dim npaRegex As RegExp: Set npaRegex = GlobalNPARegex
'
' Dim aPar As Word.Paragraph
' Dim parRng As Word.Range
' Dim matches As Object
' Dim nMatch&
' For Each aPar In ActiveDocument.Paragraphs
' Set parRng = aPar.Range
' Dim sTxt$: sTxt = FixSpecialSymbols(parRng.Text)
' Set matches = npaRegex.Execute(sTxt)
' For nMatch = 1 To matches.Count Step 1
' Dim findRng As Word.Range: Set findRng = parRng.Duplicate
' Call findRng.MoveStart(wdCharacter, InStr(1, sTxt, matches.Item(nMatch - 1).SubMatches(0)))
' Call findRng.Collapse(wdCollapseStart)
' Call findRng.MoveEnd(wdCharacter, Len(matches.Item(nMatch - 1).SubMatches(0)))
' Call frags.AddItem(findRng.Start, findRng.End, 0)
' Next nMatch
' Next aPar
'
' If frags.data_.Count > 0 Then _
' P_GetNPAFromActive = frags.AsFlatData
'End Function
'
'

38
src/addin/UIState.cls Normal file
View File

@ -0,0 +1,38 @@
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "UIState"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Public ribbon_ As API_Ribbon
Public detector_ As TDetector
Public detectionParam_ As String
Public color_ As TColor
Public transformParam_ As String
Public category_ As Long
Private Sub Class_Initialize()
detector_ = T_DETECTOR_REGEX
color_ = T_COLOR_YELLOW
transformParam_ = vbNullString
detectionParam_ = vbNullString
category_ = 0
Set ribbon_ = New API_Ribbon
End Sub
Public Function GetOptions() As ExtractionOptions
Set GetOptions = New ExtractionOptions
GetOptions.detector_ = detector_
GetOptions.param_ = detector_
GetOptions.transform_ = transformParam_
GetOptions.loadCategory_ = category_
End Function

View File

@ -0,0 +1,85 @@
Attribute VB_Name = "z_UIMessages"
' Messaging module
Option Private Module
Option Explicit
Public Enum MsgCode
' EM_COMBO_TAKEN = ERR_COMBO_TAKEN
EM_RIBBON_NOT_REACHABLE = 1
EM_SELECTION_EMPTY
IM_MARKDOWN_COMPLETE
IM_PARSE_MORPHO
IM_NO_PARSER_DATA
IM_TEST_FAILED
IM_PARSED_DESCRIPTION
IM_EXPORT_COMPLETE
IM_TRANSFORM_COMPLETE
' QM_CONFIG_EDIT_CONFIRM
End Enum
Private g_UI As API_UserInteraction
Public Function UserInteraction() As API_UserInteraction
If g_UI Is Nothing Then _
Set g_UI = New API_UserInteraction
Set UserInteraction = g_UI
End Function
Public Function SetUserInteraction(newUI As API_UserInteraction)
Set g_UI = newUI
End Function
Public Function ProcessErrorMessages(expectedErrors As Scripting.Dictionary)
If Err.Number = 0 Then _
Exit Function
Call Unload(CSE_ProgressBar)
If Not expectedErrors.Exists(Err.Number) Then _
Call Err.Raise(Err.Number)
Call UserInteraction.ShowMessage(Err.Number, Err.Source)
End Function
Public Function UIShowMessage(theCode As MsgCode, ParamArray params() As Variant)
Dim unwrapped As Variant: unwrapped = params
unwrapped = FixForwardedParams(unwrapped)
Select Case theCode
Case EM_RIBBON_NOT_REACHABLE
Call MsgBox("Íå óäàëîñü âîññòàíîâèòü ñâÿçü ñ ëåíòîé!" & vbNewLine & _
"Ïîæàëóéñòà, çàêðîéòå âñå îêíà Word äëÿ âîññòàíîâëåíèÿ êîððåêòíîé ðàáîòû è ñîîáùèòå ðàçðàáîò÷èêó", vbExclamation)
Case EM_SELECTION_EMPTY: Call MsgBox("Âûäåëåííûé ôðàãìåíò íå ñîäåðæèò òåêñòà", vbExclamation)
Case IM_MARKDOWN_COMPLETE: Call MsgBox(Fmt("Ðàçìå÷åíî âõîæäåíèé: {1}", unwrapped), vbInformation)
Case IM_PARSE_MORPHO: Call MsgBox(Fmt("Òåãè ðàçáîðà: {1}", unwrapped), vbInformation)
Case IM_NO_PARSER_DATA: Call MsgBox(Fmt("Äîïîëíèòåëüíûå äàííûå îòñóòñòâóþò: {1}", unwrapped), vbInformation)
Case IM_TEST_FAILED: Call MsgBox(Fmt("Âûäåëåííûé òåêñò íå ñîîòâåòñòâóåò òèïó: {1}", unwrapped), vbInformation)
Case IM_EXPORT_COMPLETE: Call MsgBox("Ýêñïîðò çàâåðøåí", vbInformation)
Case IM_TRANSFORM_COMPLETE: Call MsgBox(Fmt("Îñóùåñòâëåííî ïðåîáðàçîâàíèé: {1}", unwrapped), vbInformation)
Case IM_PARSED_DESCRIPTION: Call MsgBox(Fmt("Èñõîäíûé òåêñò: {1}" & vbNewLine & _
"Òèï ðàçáîðà: {2}" & vbNewLine & _
"Äîïîëíèòåëüíûå äàííûå" & vbNewLine & "{3}", unwrapped), vbInformation)
Case Else: Call MsgBox("Íåâåðíûé êîä ñîîáùåíèÿ", vbCritical)
End Select
End Function
Public Function UIAskQuestion(theCode As MsgCode, ParamArray params() As Variant) As Boolean
Dim unwrapped As Variant: unwrapped = params
unwrapped = FixForwardedParams(unwrapped)
Dim answer&: answer = vbNo
Select Case theCode
' Case QM_CONFIG_EDIT_CONFIRM
' answer = MsgBox("Âíèìàíèå! Âû íà÷èíàåòå èçìåíåíèå ëîêàëüíîé êîíôèãóðàöèè ðàçìåòêè. Ýòè èçìåíåíèÿ íå áóäóò îòðàæàòüñÿ äëÿ äðóãèõ ïîëüçîâàòåëåé" & _
' vbNewLine & "Äëÿ èçìåíåíèÿ ñåðâåðíîé êîíôèãóðàöèè îáðàòèòåñü ê ðàçðàáîò÷èêó", vbYesNo + vbQuestion)
Case Else
Call MsgBox("Invalid message code", vbCritical)
End Select
UIAskQuestion = answer = vbYes
End Function

117
src/addin/z_UIRibbon.bas Normal file
View File

@ -0,0 +1,117 @@
Attribute VB_Name = "z_UIRibbon"
' Îáðàáîòêà íàæàòèé íà êíîïêè â ðèááîíå
Option Explicit
Global g_UIState As UIState
Public Function GetUIState() As UIState
If g_UIState Is Nothing Then
Set g_UIState = New UIState
Call g_UIState.ribbon_.LoadFrom(RibbonTempFile)
' Call UIUpdateConfigList
End If
Set GetUIState = g_UIState
If g_UIState.ribbon_.Value Is Nothing Then _
Call UserInteraction.ShowMessage(EM_RIBBON_NOT_REACHABLE)
End Function
Public Sub Parse_LoadRibbon(aRibbon As IRibbonUI)
Set g_UIState = New UIState
Call g_UIState.ribbon_.Init(aRibbon, RibbonTempFile)
'Call UIUpdateConfigList
End Sub
Public Sub Parse_OnBtn(iControl As IRibbonControl)
Call EnsureGlobalState
Select Case iControl.ID
Case "NextFragment": Call RunNextFragment
Case "PrevFragment": Call RunPrevFragment
Case "BrowseFile": Call RunBrowseFile
Case "MorphoParse": Call RunMorphoParse
Case "ContextInfo": Call RunContextInfo
Case "MarkWord": Call RunMarkWord
Case "MarkParagraph": Call RunMarkParagraph
Case "TransformSingle": Call RunTransformSingle
Case "TransformAll": Call RunTransformAll
Case "ExportAll": Call RunExportAll
Case "ExportRanges": Call RunExportRanges
Case "ViewHelp": Call RunHelp
End Select
End Sub
Public Function ParseUI_DetectorCount(iControl As IRibbonControl, ByRef nCount)
nCount = TDetector.[_Last]
End Function
Public Function ParseUI_DetectorLabel(iControl As IRibbonControl, nIndex%, ByRef vLabel)
vLabel = DetectorToStr(nIndex + 1)
End Function
Public Function ParseUI_DetectorGetSelectedIndex(iControl As IRibbonControl, ByRef nValue)
Call EnsureGlobalState
nValue = g_UIState.detector_ - 1
End Function
Public Function ParseUI_DetectorChange(iControl As IRibbonControl, sID$, nIndex As Variant)
Call EnsureGlobalState
g_UIState.detector_ = nIndex + 1
' Do any UI updates needed on entity switch
End Function
Public Function ParseUI_ParamText(iControl As IRibbonControl, ByRef vLabel)
vLabel = GetUIState.detectionParam_
End Function
Public Function ParseUI_ParamChange(iControl As IRibbonControl, sParam$)
Call EnsureGlobalState
g_UIState.detectionParam_ = sParam
End Function
Public Function ParseUI_TransformText(iControl As IRibbonControl, ByRef vLabel)
vLabel = GetUIState.transformParam_
End Function
Public Function ParseUI_TransformChange(iControl As IRibbonControl, sParam$)
Call EnsureGlobalState
g_UIState.transformParam_ = sParam
End Function
Public Function ParseUI_CategoryText(iControl As IRibbonControl, ByRef vLabel)
vLabel = GetUIState.category_
End Function
Public Function ParseUI_CategoryChange(iControl As IRibbonControl, sParam$)
Call EnsureGlobalState
g_UIState.category_ = sParam
End Function
Public Function ParseUI_MarkupCount(iControl As IRibbonControl, ByRef nCount)
nCount = TColor.[_Last]
End Function
Public Function ParseUI_MarkupLabel(iControl As IRibbonControl, nIndex%, ByRef vLabel)
vLabel = ColorToStr(nIndex + 1)
End Function
Public Function ParseUI_MarkupGetSelectedIndex(iControl As IRibbonControl, ByRef nValue)
Call EnsureGlobalState
nValue = g_UIState.color_ - 1
End Function
Public Function ParseUI_MarkupChange(iControl As IRibbonControl, sID$, nIndex As Variant)
Call EnsureGlobalState
g_UIState.color_ = nIndex + 1
End Function
' =============
Private Function EnsureGlobalState() As Boolean
EnsureGlobalState = Not GetUIState Is Nothing
End Function
Private Function RibbonTempFile() As String
RibbonTempFile = Environ("TEMP") & "/" & TEMP_FILE_NAME & CStr(GetCurrentProcessId) & ".txt"
End Function

View File

@ -0,0 +1,66 @@
Attribute VB_Name = "DataAccess"
Option Explicit
Option Private Module
' TODO: incapsulate into DB class
Private Const SHEET_SOURCE = "Èñòî÷íèêè"
Private Const SHEET_DATA = "Äàííûå"
Public Function DataSheet() As Excel.Worksheet
Set DataSheet = ThisWorkbook.Sheets(SHEET_DATA)
End Function
Public Function SourceSheet() As Excel.Worksheet
Set SourceSheet = ThisWorkbook.Sheets(SHEET_SOURCE)
End Function
Public Function AddSource(target As Word.Document) As Long
AddSource = SourceSheet.Cells(GetRowFor(target.FullName), SS_ID)
End Function
Public Function SourceFileFor(sourceID&) As String
Dim foundRng As Excel.Range
Set foundRng = SourceSheet.Columns(SS_ID).Find(sourceID, LookAt:=xlWhole)
If foundRng Is Nothing Then _
Exit Function
SourceFileFor = SourceSheet.Cells(foundRng.Row, SS_PATH)
End Function
Public Function RowFor(sourceID&) As Long
Dim foundRng As Excel.Range
Set foundRng = SourceSheet.Columns(SS_ID).Find(sourceID, LookAt:=xlWhole)
If foundRng Is Nothing Then _
Exit Function
RowFor = foundRng.Row
End Function
' ====
Private Function GetNextID() As Long
Dim docsSht As Excel.Worksheet: Set docsSht = SourceSheet
Dim nRow&: nRow = DEFAULT_FIRST_ROW
Dim theID&: theID = 1
Do While docsSht.Cells(nRow, SS_ID) <> vbNullString
If theID >= docsSht.Cells(nRow, SS_ID) Then _
theID = docsSht.Cells(nRow, SS_ID) + 1
nRow = nRow + 1
Loop
GetNextID = theID
End Function
Private Function GetRowFor(target$) As Long
Dim theSheet As Excel.Worksheet: Set theSheet = SourceSheet
Dim foundRng As Excel.Range
Set foundRng = theSheet.Columns(SS_PATH).Find(target, LookAt:=xlWhole)
If foundRng Is Nothing Then
Dim nRow&: nRow = theSheet.Columns(SS_ID).Find(vbNullString, LookAt:=xlWhole).Row
theSheet.Cells(nRow, SS_ID) = GetNextID
theSheet.Cells(nRow, SS_PATH) = target
Call theSheet.Cells(nRow, SS_PATH).Hyperlinks.Add(theSheet.Cells(nRow, SS_PATH), target)
GetRowFor = nRow
Else
GetRowFor = foundRng.Row
End If
End Function

View File

@ -0,0 +1,38 @@
Attribute VB_Name = "Declarations"
Option Explicit
Option Private Module
' Ñòðóêòóðà ñòðàíèöû äàííûõ
Public Enum DataStruct
[_First] = 1
DS_ID = 1
DS_START = 2
DS_END = 3
DS_TYPE = 4
DS_TEXT = 5
[_Last] = 5
End Enum
' Ñòðóêòóðà ñòðàíèöû èñòî÷íèêîâ
Public Enum SourceStruct
[_First] = 1
SS_ID = 1
SS_PATH = 2
SS_NAME = 3
SS_PARS = 4
SS_TIME = 5
SS_COUNT = 6
[_Last] = 6
End Enum
Public Const FUNC_PARSE = "ExportAllData"
Public Const ADDIN_FILENAME = "Parsers.dotm"
Public Const DOC_MASK = "*.doc*"
Public Const DEFAULT_FIRST_ROW = 2
Public Const INVALID_ROW = -1

View File

@ -0,0 +1,50 @@
Attribute VB_Name = "DevHelper"
Option Explicit
Private Const TEST_BASIC_PARSE = "TestBasic.docx"
Private Const ADDIN_FILE = "Parsers.dotm"
Private g_RemoveAddin As Boolean
Public Function Dev_PrepareSkeleton()
Call ClearAll
End Function
Public Sub Dev_ManualRunTest()
Dim sSuite$: sSuite = "s_WordInteractions"
Dim sTest$: sTest = "t_ImportDates"
Dim sMsg$: sMsg = Dev_RunTestDebug(sSuite, sTest)
Debug.Print sMsg
Call MsgBox(sMsg)
End Sub
Public Function Dev_GetTestSuite(sName$) As Object
Select Case sName
Case "s_WordInteractions": Set Dev_GetTestSuite = New s_WordInteractions
End Select
End Function
Public Function GetTestFile() As String
Dim fso As New Scripting.FileSystemObject
GetTestFile = ThisWorkbook.Path & "\test\" & TEST_BASIC_PARSE
End Function
Public Function SetupTestAddin()
Dim fso As New Scripting.FileSystemObject
Dim sLocal$: sLocal = ThisWorkbook.Path & "\Íàäñòðîéêà\" & ADDIN_FILE
Dim sAppAddin$: sAppAddin = GetGlobalAddin
g_RemoveAddin = Not fso.FileExists(sAppAddin)
Call CopyFileOrFolder(sLocal, sAppAddin, fso)
End Function
Public Function TeardownTestAddin()
Dim fso As New Scripting.FileSystemObject
On Error Resume Next
If g_RemoveAddin Then _
Call fso.DeleteFile(GetGlobalAddin)
End Function
' ======
Private Function GetGlobalAddin() As String
GetGlobalAddin = VBA.Environ$("APPDATA") & "\Microsoft\Word\STARTUP\" & ADDIN_FILE
End Function

View File

@ -0,0 +1,92 @@
VERSION 5.00
Begin {C62A69F0-16DC-11CE-9E98-00AA00574A4F} ImportDlg
Caption = "Âûáîð èñòî÷íèêà äàííûõ"
ClientHeight = 2805
ClientLeft = 120
ClientTop = 465
ClientWidth = 6780
OleObjectBlob = "ImportDlg.frx":0000
StartUpPosition = 1 'CenterOwner
End
Attribute VB_Name = "ImportDlg"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit
Public isCancelled_ As Boolean
Public isFolder_ As Boolean
Private Sub UserForm_Initialize()
Dim nType As TDetector
For nType = TDetector.[_First] To TDetector.[_Last]
Call CBType.AddItem(DetectorToStr(nType))
Next nType
isFolder_ = False
isCancelled_ = True
TBCategory.Value = 0
End Sub
Private Sub UserForm_Terminate()
isCancelled_ = True
Call Me.Hide
End Sub
Public Property Get FileName() As String
FileName = TBDocument.Text
End Property
Public Property Get Options() As ExtractionOptions
Set Options = New ExtractionOptions
Options.detector_ = CBType.ListIndex + 1
Options.param_ = TBParam.Text
Options.transform_ = TBTransform.Text
Options.loadCategory_ = TBCategory.Value
End Property
' ============
Private Sub DocumentBtn_Click()
Dim sFile$: sFile = UserInteraction.PromptFileFilter( _
ThisWorkbook.Path & "\", _
sDescription:="Äîêóìåíò Word", _
sFilter:="*.docx;*.doc;*.docm")
If sFile = vbNullString Then _
Exit Sub
isFolder_ = False
TBDocument.Text = sFile
End Sub
Private Sub ParameterBtn_Click()
Dim sFile$: sFile = UserInteraction.PromptFileFilter( _
ThisWorkbook.Path & "\", _
"All files", _
"*.*")
If sFile = vbNullString Then _
Exit Sub
TBParam.Text = sFile
End Sub
Private Sub FolderBtn_Click()
Dim sFile$: sFile = UserInteraction.PromptFolder(ThisWorkbook.Path & "\")
If sFile = vbNullString Then _
Exit Sub
isFolder_ = True
TBDocument.Text = sFile
End Sub
Private Sub CancelBtn_Click()
isCancelled_ = True
Call Me.Hide
End Sub
Private Sub OkBtn_Click()
If FileName = vbNullString Or CBType.ListIndex = -1 Then
Call UserInteraction.ShowMessage(EM_VALIDATION_FAIL)
Exit Sub
End If
isCancelled_ = False
Call Me.Hide
End Sub

BIN
src/database/ImportDlg.frx Normal file

Binary file not shown.

62
src/database/Main.bas Normal file
View File

@ -0,0 +1,62 @@
Attribute VB_Name = "Main"
Option Explicit
Option Private Module
Public Const PRODUCT_VERSION = "1.3.0"
Public Const PRODUCT_NAME = "Concept-Mining"
Public g_VersionTimer As Long
Public Sub Auto_Open()
Dim sCmd$: sCmd = OfficeCommandLine
If VBA.InStr(1, sCmd, "/automation", vbTextCompare) <> 0 Then _
Exit Sub
g_VersionTimer = SetTimer(0, 0, CP_VERSION_MSG_DELAY, AddressOf OnVersionCheck)
End Sub
Public Function OnVersionCheck(ByVal nHwnd As Long, ByVal uMsg As Long, ByVal nEvent As Long, ByVal nTime As Long)
Call KillTimer(0, g_VersionTimer)
Call VersionValidate(PRODUCT_NAME, PRODUCT_VERSION)
End Function
Public Sub RunImportWord()
If Not EnsureAddinInstalled Then _
Exit Sub
Call ImportDlg.Show
If ImportDlg.isCancelled_ Then
Unload ImportDlg
Exit Sub
End If
Dim iParams As ExtractionOptions: Set iParams = ImportDlg.Options
Dim sPath$: sPath = ImportDlg.FileName
Dim bIsFolder As Boolean: bIsFolder = ImportDlg.isFolder_
Call Unload(ImportDlg)
Dim nCount&: nCount = ProcessImports(sPath, bIsFolder, iParams)
Call UserInteraction.ShowMessage(IM_IMPORT_COMPLETE, nCount)
End Sub
Public Sub RunFollowLink()
Dim theSheet As Excel.Worksheet: Set theSheet = DataSheet
If ThisWorkbook.ActiveSheet.Name <> theSheet.Name Then
Call UserInteraction.ShowMessage(EM_EXPECTED_DATASHEET)
Exit Sub
End If
Dim nRow&: nRow = ThisWorkbook.Application.Selection.Cells(1, 1).Row
Dim srcID$: srcID = theSheet.Cells(nRow, DS_ID)
If srcID = vbNullString Or Not IsNumeric(srcID) Then
Call UserInteraction.ShowMessage(EM_INVALID_SOURCE_ID)
Exit Sub
End If
Call FollowLinkAt(CLng(srcID), theSheet.Cells(nRow, DS_START), theSheet.Cells(nRow, DS_END))
End Sub
Public Sub RunClearAll()
Call ClearAll
Call UserInteraction.ShowMessage(IM_CLEAR_ALL)
End Sub

152
src/database/MainImpl.bas Normal file
View File

@ -0,0 +1,152 @@
Attribute VB_Name = "MainImpl"
Option Explicit
Option Private Module
Public Function EnsureAddinInstalled() As Boolean
Dim sPath$: sPath = Environ("APPDATA") & "\Microsoft\Word\STARTUP\" & ADDIN_FILENAME
Dim fso As New Scripting.FileSystemObject
EnsureAddinInstalled = fso.FileExists(sPath)
If Not EnsureAddinInstalled Then _
Call UserInteraction.ShowMessage(EM_NO_ADDIN)
End Function
Public Function ClearAll()
SourceSheet.UsedRange.Offset(1).ClearContents
DataSheet.UsedRange.Offset(1).ClearContents
End Function
Private Function ScanDocsFolder(target$) As Collection
Set ScanDocsFolder = New Collection
Dim sFolder$: sFolder = target & "\"
Dim sFile$: sFile = Dir(sFolder & DOC_MASK)
Do While Len(sFile) > 0 And sFile <> sFolder
Call ScanDocsFolder.Add(sFolder & sFile)
sFile = Dir
Loop
End Function
Public Function ProcessImports(sPath$, bIsFolder As Boolean, params As ExtractionOptions, Optional bSilent As Boolean = False) As Long
Dim wordApp As New API_WordWrapper: Call wordApp.CreateApplication(bIsVisible:=False)
If bSilent Then _
Call wordApp.DisableMessages
Dim xlUI As New API_XLWrapper: Call xlUI.SetApplication(ThisWorkbook.Application)
Call xlUI.PauseUI
ThisWorkbook.Application.DisplayAlerts = False
Dim nCount&: nCount = 0
Dim theDoc As Word.Document
If Not bIsFolder Then
Set theDoc = wordApp.OpenDocument(sPath, bReadOnly:=True)
If theDoc Is Nothing Then _
GoTo SAFE_EXIT
nCount = nCount + ScanDataFrom(wordApp, params)
Call wordApp.ReleaseDocument
Else
Dim docs As Collection: Set docs = ScanDocsFolder(sPath)
Call CSE_ProgressBar.Init("Îáðàáîòêà äîêóìåíòîâ", maxVal:=docs.Count - 1, canInterrupt:=True)
If Not bSilent Then _
Call CSE_ProgressBar.Show
Dim sFile As Variant
For Each sFile In docs
Set theDoc = wordApp.OpenDocument(CStr(sFile), bReadOnly:=True)
If theDoc Is Nothing Then _
GoTo SAFE_EXIT
theDoc.Range.NoProofing = True
CSE_ProgressBar.Description = theDoc.Name
nCount = nCount + ScanDataFrom(wordApp, params)
Call wordApp.ReleaseDocument(bCloseApplication:=False)
Call CSE_ProgressBar.IncrementA
If CSE_ProgressBar.Interrupted Then _
Exit For
Next sFile
Call Unload(CSE_ProgressBar)
End If
SAFE_EXIT:
ThisWorkbook.Application.DisplayAlerts = True
Call xlUI.ResumeUI
Call wordApp.ReleaseApplication
ProcessImports = nCount
End Function
Public Function FollowLinkAt(target&, nStart&, nEnd&)
Dim sPath$: sPath = SourceFileFor(target)
If sPath = vbNullString Then
Call UserInteraction.ShowMessage(EM_INVALID_SOURCE_ID)
Exit Function
End If
Dim fso As New Scripting.FileSystemObject
If Not fso.FileExists(sPath) Then
Call UserInteraction.ShowMessage(EM_INVALID_PATH, sPath)
Exit Function
End If
Dim wordApp As New API_WordWrapper
Dim theDoc As Word.Document: Set theDoc = wordApp.OpenDocument(sPath)
If theDoc Is Nothing Then _
Exit Function
If theDoc.Range.End < nEnd Then
Call UserInteraction.ShowMessage(EM_INVALID_LINK, sPath)
Exit Function
End If
Dim targetRng As Word.Range: Set targetRng = theDoc.Range(nStart, nEnd)
Call targetRng.Select
Call theDoc.ActiveWindow.ScrollIntoView(targetRng)
Call wordApp.Application.Activate
End Function
' ======
Private Function ScanDataFrom(target As API_WordWrapper, params As ExtractionOptions) As Long
Dim dataSht As Excel.Worksheet: Set dataSht = DataSheet
Dim srcSht As Excel.Worksheet: Set srcSht = SourceSheet
Dim theTimer As New API_Timer
Call theTimer.Start
Call target.Document.Activate
Dim srcID&: srcID = AddSource(target.Document)
Dim srcRow: srcRow = RowFor(srcID)
Dim nCount&: nCount = 0
Dim newData As Variant
Call target.Document.Activate
On Error GoTo EXIT_FUNCTION
newData = target.Run(FUNC_PARSE, params.AsFlatData)
On Error GoTo 0
If ArraySize(newData) <= 0 Then _
Exit Function
Dim nRow&: nRow = dataSht.Columns(DS_ID).Find(vbNullString, LookAt:=xlWhole).Row
Dim nDataRow&
Dim nDataCol&
For nDataRow = LBound(newData, 1) To UBound(newData, 1) Step 1
dataSht.Cells(nRow, DS_ID) = srcID
Dim nCol&: nCol = DS_ID + 1
For nDataCol = LBound(newData, 2) To UBound(newData, 2) Step 1
dataSht.Cells(nRow, nCol) = newData(nDataRow, nDataCol)
nCol = nCol + 1
Next nDataCol
nRow = nRow + 1
nCount = nCount + 1
Next nDataRow
srcSht.Cells(srcRow, SS_TIME) = theTimer.TimeElapsed
srcSht.Cells(srcRow, SS_COUNT) = nCount
srcSht.Cells(srcRow, SS_NAME) = target.Document.Name
srcSht.Cells(srcRow, SS_PARS) = target.Document.Paragraphs.Count
EXIT_FUNCTION:
ScanDataFrom = nCount
End Function

View File

@ -0,0 +1,6 @@
Attribute VB_Name = "ManualSubs"
Option Explicit
Public Sub RunClear()
Call ClearAll
End Sub

View File

@ -0,0 +1,69 @@
Attribute VB_Name = "z_UIMessages"
' Messaging module
Option Private Module
Option Explicit
Public Enum MsgCode
MSG_OK = 0
EM_EXPECTED_DATASHEET
EM_NO_ADDIN
EM_INVALID_SOURCE_ID
EM_INVALID_PATH
EM_INVALID_LINK
EM_VALIDATION_FAIL
IM_IMPORT_COMPLETE
IM_CLEAR_ALL
'QM_ADD_TITLELINK
End Enum
Private g_UI As API_UserInteraction
Public Function UserInteraction() As API_UserInteraction
If g_UI Is Nothing Then _
Set g_UI = New API_UserInteraction
Set UserInteraction = g_UI
End Function
Public Function SetUserInteraction(newUI As API_UserInteraction)
Set g_UI = newUI
End Function
Public Function UIShowMessage(theCode As MsgCode, ParamArray params() As Variant)
Dim unwrapped As Variant: unwrapped = params
unwrapped = FixForwardedParams(unwrapped)
Select Case theCode
Case EM_EXPECTED_DATASHEET: Call MsgBox("Äàííàÿ ôóíêöèÿ äîñòóïíà òîëüêî äëÿ ëèñòà ""Äàííûå""", vbExclamation)
Case EM_NO_ADDIN: Call MsgBox("Âíèìàíèå! Äëÿ êîððåêòíîé ðàáîòû ïàðñåðîâ íåîáõîäèìî óñòàíîâèòü íàäñòðîéêó äëÿ Word", vbCritical)
Case EM_INVALID_SOURCE_ID: Call MsgBox("Âûäåëèòå ñòðîêó ñ êîððåêòíûì èäåíòèôèêàòîðîì èñòî÷íèêà", vbExclamation)
Case EM_INVALID_PATH: Call MsgBox(Fmt("Ôàéë íå zñóùåñòâóåò: {1}", unwrapped), vbExclamation)
Case EM_INVALID_LINK: Call MsgBox(Fmt("Äèàïàçîí ññûëêè èìååò êîîðäèíàòû, ïðåâûøàþùèå ðàçìåð îòêðûòîãî ôàéëà {1}", unwrapped), vbExclamation)
Case EM_VALIDATION_FAIL: Call MsgBox("Çàïîëíèòå âñå ïîëÿ", vbExclamation)
Case IM_IMPORT_COMPLETE: Call MsgBox(Fmt("Èìïîðò äàííûõ ïðîèçâåäåí óñïåøíî" & vbNewLine & "Äîáàâëåíî ñòðîê: {1}", unwrapped), vbInformation)
Case IM_CLEAR_ALL: Call MsgBox("Âñå äàííûå óäàëåíû", vbInformation)
Case Else
Call MsgBox("Íåâåðíûé êîä ñîîáùåíèÿ", vbCritical)
End Select
End Function
Public Function UIAskQuestion(theCode As MsgCode, ParamArray params() As Variant) As Boolean
Dim unwrapped As Variant: unwrapped = params
unwrapped = FixForwardedParams(unwrapped)
Dim answer As Long: answer = vbNo
Select Case theCode
' Case QM_ADD_TITLELINK
' answer = MsgBox("Âíèìàíèå! Âû äîáàâëÿåòå äîêóìåíò íå èç ÃÀÐÀÍÒà" & vbNewLine & _
' "Äëÿ íåãî ñãåíåðèðîâàí ID: " & p1 & vbNewLine & _
' "Â ïåðâûé àáçàö áóäåò äîáàâëåíà ñîîòâåòñòâóþùàÿ ññûëêà. Ïðîäîëæèòü?", vbYesNo + vbQuestion)
Case Else
Call MsgBox("Íåâåðíûé êîä ñîîáùåíèÿ", vbCritical)
End Select
UIAskQuestion = answer = vbYes
End Function

View File

@ -0,0 +1,11 @@
Attribute VB_Name = "z_UIRibbon"
' Îáðàáîòêà íàæàòèé íà êíîïêè â ðèááîíå
Option Explicit
Sub OnRibbonBtn(control As IRibbonControl)
Select Case control.ID
Case "ImportWord": Call RunImportWord
Case "FollowLink": Call RunFollowLink
Case "ClearAll": Call RunClearAll
End Select
End Sub

View File

@ -0,0 +1,56 @@
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "s_WordInteractions"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Public Function Setup()
Call SetupTestAddin
End Function
Public Function Teardown()
Call TeardownTestAddin
Call ClearAll
End Function
Public Function t_ImportInvalid()
On Error GoTo PROPAGATE_ERROR
Dim iParams As New ExtractionOptions
iParams.detector_ = T_DETECTOR_DATE
Call Dev_NewCase("No file")
Call Dev_ExpectEQ(ProcessImports("invalid.txt", False, iParams, bSilent:=True), 0)
Call Dev_ExpectEQ(SourceSheet.Cells(2, 1), "")
Call Dev_NewCase("Invalid detector")
iParams.detector_ = T_DETECTOR_UNKNOWN
Call Dev_ExpectEQ(ProcessImports(GetTestFile, False, iParams, bSilent:=True), 0)
Call Dev_NewCase("Invalid parameter")
iParams.detector_ = T_DETECTOR_LIST
iParams.param_ = "invalid.txt"
Call Dev_ExpectEQ(ProcessImports(GetTestFile, False, iParams, bSilent:=True), 0)
Exit Function
PROPAGATE_ERROR:
Call Dev_LogError(Err.Number, Err.Description)
End Function
Public Function t_ImportDates()
On Error GoTo PROPAGATE_ERROR
Dim iParams As New ExtractionOptions
iParams.detector_ = T_DETECTOR_DATE
Call Dev_ExpectEQ(ProcessImports(GetTestFile, False, iParams, bSilent:=True), 4)
Call Dev_ExpectNE(SourceSheet.Cells(2, 1), "")
Exit Function
PROPAGATE_ERROR:
Call Dev_LogError(Err.Number, Err.Description)
End Function

BIN
test/TestBasic.docx Normal file

Binary file not shown.

2
ui/addin/.rels Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/><Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId5" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId4" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="customUI/customUI.xml"/></Relationships>

108
ui/addin/customUI.xml Normal file
View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"
onLoad="Parse_LoadRibbon" >
<ribbon>
<tabs>
<tab id="MiningTab" label="МАЙНИНГ">
<group id="DetectionGroup" label="Извлечение">
<dropDown id="DetectorPicker" sizeString="WWWWWWWW"
label = "Способ"
getItemCount="ParseUI_DetectorCount"
getItemLabel="ParseUI_DetectorLabel"
getSelectedItemIndex="ParseUI_DetectorGetSelectedIndex"
onAction ="ParseUI_DetectorChange"/>
<editBox id="ParamInput" sizeString="WWWWWWWWW"
label = "Параметр"
getText="ParseUI_ParamText"
onChange="ParseUI_ParamChange"/>
<buttonGroup id="NavigationBtns">
<button id="NextFragment"
supertip="Следующее вхождение"
imageMso="_3DPerspectiveDecrease"
onAction="Parse_OnBtn"/>
<button id="PrevFragment"
supertip="Предыдущее вхождение"
imageMso="_3DPerspectiveIncrease"
onAction="Parse_OnBtn"/>
<button id="BrowseFile"
supertip="Выбрать файл в качестве параметра"
imageMso="AlwaysMoveConversation"
onAction="Parse_OnBtn"/>
<button id="MorphoParse"
supertip="Разбор выделенного слова / фразы"
imageMso="ActiveXLabel"
onAction="Parse_OnBtn"/>
<button id="ContextInfo"
supertip="Извлеченные данные из выделенного фрагмента"
imageMso="ARMPreviewButton"
onAction="Parse_OnBtn"/>
</buttonGroup>
</group>
<group id="MarkdownGroup" label="Отображение">
<dropDown id="ColorPicker" sizeString="WWWWW"
label = "Выделение"
getItemCount="ParseUI_MarkupCount"
getItemLabel="ParseUI_MarkupLabel"
getSelectedItemIndex="ParseUI_MarkupGetSelectedIndex"
onAction ="ParseUI_MarkupChange"/>
<button id="MarkWord"
label="Вхождения"
supertip="Выделить вхождения сущностей"
imageMso="AsianLayoutPhoneticGuide"
onAction="Parse_OnBtn"/>
<button id="MarkParagraph"
label="Абзацы"
supertip="Выделить абзацы, содержащие выбранные сущности"
imageMso="AlignJustifyHigh"
onAction="Parse_OnBtn"/>
</group>
<group id="TransformGroup" label="Преобразование">
<editBox id="TransformInput" sizeString="WWWWWWW"
label = "Параметр"
getText="ParseUI_TransformText"
onChange="ParseUI_TransformChange"/>
<button id="TransformSingle"
label="Преобразовать один"
supertip="Провести преобразование выделенной сущности (используйте навигацию)"
imageMso="FontsReplaceFonts"
onAction="Parse_OnBtn"/>
<button id="TransformAll"
label="Преобразовать все"
supertip="Провести преобразования всех сущностей"
imageMso="AsianLayoutMenu"
onAction="Parse_OnBtn"/>
</group>
<group id="LoadGroup" label="Выгрузка">
<editBox id="CategoryInput" sizeString="WWW"
label = "Категория"
getText="ParseUI_CategoryText"
onChange="ParseUI_CategoryChange"/>
<button id="ExportAll"
label="Выгрузить все"
supertip="Выгрузить вхождения с текстами"
imageMso="ExportExcel"
onAction="Parse_OnBtn"/>
<button id="ExportRanges"
label="Только вхождения"
supertip="Выгрузить информацию о вхождениях (без текста)"
imageMso="MindMapExportExcel"
onAction="Parse_OnBtn"/>
</group>
<group id="MiscGroup" label="Информация">
<button id="ViewHelp" size="large"
label="Справка"
supertip="Вызов справки"
imageMso="Info"
onAction="Parse_OnBtn"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>

2
ui/database/.rels Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/><Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId5" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId4" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="customUI/customUI.xml"/></Relationships>

29
ui/database/customUI.xml Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" >
<ribbon>
<tabs>
<tab id="MarkupAggregator" label="Концепт.Майнинг" >
<group id="Actions" label="Действия" >
<button id="ImportWord" visible="true" size="large"
label="Обработать источники"
supertip="Загрузить данные из текстовых документов"
onAction="OnRibbonBtn"
imageMso="ExportWord"/>
<button id="FollowLink" visible="true" size="large"
label="Показать документ"
supertip="Открыть выделенный фрагмент в документе"
onAction="OnRibbonBtn"
imageMso="PivotTableGroupSelection"/>
<separator id="separator" />
<button id="ClearAll" visible="true" size="large"
label="Очистить"
supertip="Удалить все добавленные данные"
onAction="OnRibbonBtn"
imageMso="ArrangeByRecurrence"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>