Возможен-ли сложный парсинг TXT-файлов средствами OOo BASIC

Автор Dr_Lecter, 4 октября 2015, 19:46

0 Пользователи и 1 гость просматривают эту тему.

Dr_Lecter

Во вложении отчет по исследованию в формате TXT, полученный с ультразвукового сканера.

Необходимо обработать его так, чтобы получить практически все числовые параметры в индивидуальные переменные OOo BASIC и далее внести в шаблон заключения. Т.е. каждая цифра должна быть прочтена и присвоена определенной переменной.

Кто писал код внутри сканера и почему получается такая странная неупорядоченная структура я не знаю, но приходится работать с тем что есть.

Например в из участка:

[Длинные кости плода]  
ПлечК (Jeanty    ) : 33.31 mm,   Ср.Бер. : 21н2д+/-19д,  Процентили : 56.04  
ЛоктК (Jeanty    ) : 31.30 mm,   Ср.Бер. : 21н6д+/-22д,  Процентили : 73.07  
ББерцК (Jeanty    ) : 33.12 mm,   Ср.Бер. : 22н1д+/-21д,  Процентили : 76.55


Должны получится числовые переменные (типов Integer и Double):

ПлечеваяКостьЗначение = 33,31 (Double)
ПлечеваяКостьСрок = 149 (Integer) 'Срок беременности идет в днях поэтому недели из отчета нужно перевести в дни
ПлечеваяКостьПроцент = 0,5604 (Double)

ЛоктеваяКостьЗначение = 33,30 (Double)
ЛоктеваяКостьСрок = 153 (Integer)
ЛоктеваяКостьПроцент = 0,7307 (Double)

ЛоктеваяКостьЗначение = 33,12 (Double)
ЛоктеваяКостьСрок = 155 (Integer)
ЛоктеваяКостьПроцент = 0,7655 (Double)

А одинаковые строки из участков типа:

[Пупочная А.]  
ПСК : 13.31 cm/s    
ИС : 0.61  
ПИ : 0.97  

[Сред.мозг.арт.]  
ПСК : 25.86 cm/s    
ИС : 0.87  
ПИ : 1.92  


Должны быть распознаны отдельно и размещены в переменные типа Double:

ПупочнаяАртерияПСК = 13,31
ПупочнаяАртерияИС = 0,61
ПупочнаяАртерияПИ = 0,97

СредняяМозговаяАртерияПСК = 25,86
СредняяМозговаяАртерияИС = 0,87
СредняяМозговаяАртерияПИ = 1,92


Возможно ли подобную задачу решить средствами OOo BASIC или нет?
И если да, то с чего начать (у Питоньяка про парсинг вообще ничего не нашел). Если же нет, то чем по вашему мнению можно воспользоваться.

Спасибо!


rami

Документ не скачивается, пытался четыре раза

Dr_Lecter


Dr_Lecter

Странный глюк - отправляется, но не скачивается с форума.

Dr_Lecter

rami

Это глюк Safari с движком форума.
Скачайте через правую кнопку или Alt пунктом "Скачать файл по ссылке" но только не "Скачать файл по ссылке как"

rami

Цитата: Dr_Lecter от  4 октября 2015, 19:56Это глюк Safari с движком форума.
Может быть, недавно обновлял Safari. Firefox скачал.

bigor

А если файл загрузить во writer и обрабатывать его там.
Например:
Sub ParserScan

Dim args(1) as new com.sun.star.beans.PropertyValue

args(0).Name = "FilterName"
args(0).Value = "Text (encoded)"

args(1).Name = "FilterOptions"   'Identify character set for single-byte chars
args(1).Value = "UTF8,CRLF,Times New Roman,ru-RU,"            

ScanOut = StarDesktop.loadComponentFromUrl(ConverttoURL("c:\tools\TestPatient.txt"),"_blank",0,args())
Doc = ScanOut.Text
n=0

Cursor = Doc.createTextCursor 'создаем текстовый курсор
Cursor.GotoStart(false) 'в начало документа

Cursor.gotoNextParagraph(false)' пропускаем первую строку
Cursor.gotoNextParagraph(true)
N_klinika = ltrim((mid(Cursor.string,instr(Cursor.string,":")+2))
N_klinika = left(N_klinika, len(N_klinika)-2)

Cursor.goRight(0, False)
Cursor.gotoNextParagraph(true)
N_vrUZI = ltrim((mid(Cursor.string,instr(Cursor.string,":")+2))
N_vrUZI = left(N_vrUZI, len(N_vrUZI)-2)

Cursor.goRight(0, False)
Cursor.gotoNextParagraph(true)
N_N = ltrim((mid(Cursor.string,instr(Cursor.string,":")+2))
N_N = rtrim(left(N_N, len(N_N)-2))

Cursor.goRight(0, False)
Cursor.gotoNextParagraph(true)
DtIs = ltrim((mid(Cursor.string,instr(Cursor.string,":")+2))
DtIs = rtrim(left(DtIs, len(DtIs)-2))
' далее аналогично,
' перейдем на строку с несколькими параметрами
Do While n<26
Cursor.gotoNextParagraph(false)
n=n+1
Loop
Cursor.goRight(0, False)
Cursor.gotoNextParagraph(true)
BPR = rtrim(mid(Cursor.String, instr(Cursor.String,":")+2, instr(Cursor.String,"mm")-instr(Cursor.String,":")-2))
SrBer = rtrim(mid(Cursor.String, InStr(Cursor.String,"Ср.Бер. :")+10, instr(Cursor.String, "д,") - InStr(Cursor.String,"Ср.Бер. :")-10))
Prozentil = mid(Cursor.String, InStr(InStr(Cursor.String,"д,"),Cursor.String,":")+2)
Prozentil = rtrim(left(Prozentil, len(Prozentil)-2))

msgbox ">" & N_klinika & "<>"& N_vrUZI & "<>"& N_N & "<>"& DtIs & "<>"& BPR & "<>"& SrBer & "<>" & Prozentil &"<"
End Sub
Поддержать разработчиков LibreOffice можно можно тут, а наш форум вот тут

Dr_Lecter

Bigor

Длина строк в файлах отчетов переменная. Да и не дело это работать через GUI.

У меня есть наметки - вечером покажу, и прикину что не получается.
Идея - преобразовать файл к формату вида CSV а дальше уже проще будет.

bigor

Длина строк не важна, главное что бы их порядок не менялся
Поддержать разработчиков LibreOffice можно можно тут, а наш форум вот тут

rami

Цитата: Dr_Lecter от  5 октября 2015, 10:31У меня есть наметки - вечером покажу, и прикину что не получается.
Я уже приготовил ведро попкорна ;D
Цитата: Dr_Lecter от  5 октября 2015, 10:31Идея - преобразовать файл к формату вида CSV а дальше уже проще будет.
Форматы .txt и .csv — это фактически одно и то же, разница в том, что .txt открывается в текстовом редакторе с разбивкой по строкам, а .csv открывается в табличном редакторе с разбивкой по строкам и требует разделитель для разбивки строк по столбцам.

Преобразование имеет смысл, если вы хотите открыть .csv в Calc и обработать данные формулами, но это тот же GUI, только с другого бока.

Dr_Lecter

Bigor

Порядок и количество строк не постоянно.
И очередность разделов тоже может меняться.

rami

Попкорн это хорошо.
Но может для пущего веселья подскажите как в OOo BASIC выполнить замену типа :

Foreach-Object {$_ -replace "(\d+)яр",'$1г'}|

в строке
Возраст: 21яр4м

Чтобы получить строку
Возраст: 21г4м

В настоящий момент у меня основная проблема именно в работе с регулярными выражениями

bormant

#11
Я б пошел таким путем:
Function Split1(s as String, ByRef v as Double, ByRef b as Integer, ByRef t as Integer, ByRef p as Double) as Boolean
' разбивает на значения строку вида
' ПлечК (Jeanty    ) :\t33.31 mm,   Ср.Бер. : 21н2д+/-19д,  Процентили :\t56.04
'                       ~~~~~                 ~~ ~    ~~                  ~~~~~
Dim ta() as String, tb() as String
Split1() = False

ta() = Split(s,",")
tb() = Split(ta(0),":")
v = Val(tb(1))

tb() = Split(ta(1),":")
tb() = Split(tb(1),"-")
t = Val(tb(1))

tb() = Split(tb(0),"н")
b = Val(tb(0))
If UBound(tb())>0 Then b = b*7 + Val(tb(1))

tb() = Split(ta(2),":")
p = Val(tb(1))

Split1() = True
End Function

Function Split2(s as String, ByRef n as Double)
Dim ta() as String
Split2() = False
ta = Split(s,":")
n = Val(ta(1))
Split2() = True
End Function

Function Parse(FilePath as String) as Boolean
Dim oInputStream as Object
Dim oUcb as Object
Dim oFile as Object
Dim Section as String, s as String
Dim v as Double, b as Integer, t as Integer, p as Double

oUcb = createUnoService("com.sun.star.ucb.SimpleFileAccess")
If oUcb.Exists(FilePath) Then
oInputStream = createUnoService("com.sun.star.io.TextInputStream")
oFile = oUcb.OpenFileReadWrite(FilePath)
oInputStream.SetInputStream(oFile.GetInputStream)
While Not oInputStream.IsEOF
s = oInputStream.ReadLine
If Mid(s,1,1)="[" Then
Section = Mid(s,1,InStr(s,"]"))
Else
Select Case Section
Case "[Длинные кости плода]"
Select Case Mid(s, 1, InStr(s, " ")-1)
Case "ПлечК"
Split1(s, v, b, t, p)
Case "ЛоктК"
'Split1(s, ...)
Case "ББерцК"
'Split1(s, ...)
End Select
Case "[Пупочная А.]"
Select Case Mid(s, 1, InStr(s, " ")-1)
Case "ПСК"
'Split2(s, ...)
Case "ИС"
'Split2(s, ...)
Case "ПИ"
'Split2(s, ...)
End Select
Case "[Сред.мозг.арт.]"
Select Case Mid(s, 1, InStr(s, " ")-1)
Case "ПСК"
'Split2(s, ...)
Case "ИС"
'Split2(s, ...)
Case "ПИ"
'Split2(s, ...)
End Select
End Select
End If
Wend
oInputStream.CloseInput()
Parse() = True
Else
Parse() = False
End If
End Function
Автору на яд. Поддержать форум.

bormant

Цитата: Dr_Lecter от  5 октября 2015, 12:15в строке
Возраст: 21яр4м

Чтобы получить строку
Возраст: 21г4м

    If InStr(s, "Возраст :") = 1 Then
        i=InStr(s, "яр")
        If i>0 Then Mid(s,i,2,"г")
    End If
Автору на яд. Поддержать форум.

JohnSUN

+1
Кроме Split и Val действительно ничего не понадобится. Просто, как всё гениальное!

Доктор, а можно нескромный вопрос по теме? Откуда это непреодолимое желание сделать свой собственный велосипед? Если уж не хочется платить за Ultravision, то можно воспользоваться программами Сергея Шестопалова. Всё давно давным написано, работает в массе кабинетов УЗИ, сёстры, пациенты и - самое главное! - врачи не жалуются...
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

bormant

#14
И Split1 можно чутка поменять в части разбора ННнДДд. Если условий корректного преобразования пока не придумалось, функции можно в процедуры перевести:
Sub SplitWD(s as String, ByRef d as Integer)
' XXнYYд -> XX*7+YY
Dim a() as String
a() = Split(s, "н")
d = Val(a(0))
If UBound(a) > 0 Then d = d * 7 + Val(a(1))
End Sub

Sub Split2(s as String, ByRef n as Double)
Dim ta() as String
ta = Split(s, ":")
If UBound(ta)>0 Then n = Val(ta(1)) Else n = 0
End Sub

Sub Split1(s as String, ByRef v as Double, ByRef b as Integer, ByRef t as Integer, ByRef p as Double)
' разбивает на значения строку вида
' ПлечК (Jeanty    ) :\t33.31 mm,   Ср.Бер. : 21н2д+/-19д,  Процентили :\t56.04
'                       ~~~~~                 ~~ ~    ~~                  ~~~~~
Dim ta() as String, tb() as String
ta() = Split(s, ",")
Split2(ta(0), v)

tb() = Split(ta(1), ":")
tb() = Split(tb(1), "+/-")
SplitWD(tb(0), b)
If UBound(tb) > 0 Then SplitWD(tb(1), t) Else t = 0

Split2(ta(2), p)
End Sub
Автору на яд. Поддержать форум.