Регулярный поиск в двоичном файле
Я пытаюсь написать сценарий Excel VBA, который извлекает некоторую информацию (версию и дату редакции) из двоичного файла FrameMaker (*.fm).
Следующая подпрограмма открывает файл *.fm и записывает первые 25 строк (необходимая информация в эти первые 25 строк) в переменную.
Sub fetchDate()
Dim fso As Object
Dim fmFile As Object
Dim fileString As String
Dim fileName As String
Dim matchPattern As String
Dim result As String
Dim i As Integer
Dim bufferString As String
Set fso = CreateObject("Scripting.FileSystemObject")
fileName = "C:\FrameMaker-file.fm"
Set fmFile = fso.OpenTextFile(fileName, ForReading, False, TristateFalse)
matchPattern = "Version - Date.+?(\d{1,2})[\s\S]*Rev.+?(\d{1,2})"
fileString = ""
i = 1
Do While i <= 25
bufferString = fmFile.ReadLine
fileString = fileString & bufferString & vbNewLine
i = i + 1
Loop
fmFile.Close
'fileString = Replace(fileString, matchPattern, "")
result = regExSearch(fileString, matchPattern)
MsgBox result
Set fso = Nothing
Set fmFile = Nothing
End Sub
Функции регулярных выражений выглядят так:
Function regExSearch(ByVal strInput As String, ByVal strPattern As String) As String
Dim regEx As New RegExp
Dim strReplace As String
Dim result As String
Dim match As Variant
Dim matches As Variant
Dim subMatch As Variant
Set regEx = CreateObject("VBScript.RegExp")
If strPattern <> "" Then
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.test(strInput) Then
Set matches = regEx.Execute(strPattern)
For Each match In matches
If match.SubMatches.Count > 0 Then
For Each subMatch In match.SubMatches
Debug.Print "match:" & subMatch
Next subMatch
End If
Next match
regExSearch = result
Else
regExSearch = "no match"
End If
End If
Set regEx = Nothing
End Function
Проблема 1:
Содержимое двоичного файла *.fm, который сохраняется в переменной "fileString", отличается при каждом запуске, хотя файл *.fm остается неизменным.
Вот несколько примеров первых трех строк из разных прогонов, которые сохранены в "fileString":
пример 1
<MakerFile 12.0>
Aaÿ No.009.xxx ???? /tEXt ??????
пример 2
<MakerFile 12.0>
Aaÿ ` ? ???? /tEXt ? c ? E ? ????a A ? ? ? ? ? d??????? ? Heading ????????????A???????A
Как вы видите, пример 1 отличается от примера 2, хотя это был тот же код VBA и тот же файл *.fm.
Проблема 2:
Также большой проблемой является то, что строка поиска регулярных выражений из "matchPattern" записывается случайным образом в мою "fileString". Вот скриншот с консоли отладки:
Как это может быть? Любые предложения или идеи, чтобы решить эту проблему?
Я использую:
MS Office Профессиональный Плюс 2010
Справочник по VBA для регулярных выражений: Регулярные выражения Microsoft VBScript 5.5
Заранее большое спасибо!
С уважением, Энди
/ отредактировать 12 марта 2018 года:
Вот пример файла *.fm: пример файла. Если вы откроете его с помощью блокнота, вы можете увидеть некоторую информацию, такую как "Версия - DateVersion 4 - 2018/ февраль /07" и "Rev02 - 2018/ февраль /21" в виде простого текста. текст. Я хочу получить эту информацию с помощью регулярного выражения.
1 ответ
Я нашел решение с использованием ADODB.streams. Это отлично работает:
Sub test_binary()
Dim regEx As Object
Dim buffer As String
Dim filename As String
Dim matchPattern As String
Dim result As String
Set regEx = CreateObject("VBScript.RegExp")
filename = "C:\test.fm"
With CreateObject("ADODB.Stream")
.Open
.Type = 2
.Charset = "utf-8"
.LoadFromFile filename
buffer = .Readtext(10000)
.Close
End With
matchPattern = "Version - Date.+?(\d{1,2})[\s\S]*Rev.+?(\d{1,2})"
result = regExSearch(buffer, matchPattern)
MsgBox result
End Sub
функция регулярного выражения:
Function regExSearch(ByVal strInput As String, ByVal strPattern As String) As String
Dim regEx As New RegExp
Dim result As String
Dim match As Variant
Dim matches As Variant
Dim subMatch As Variant
Set regEx = CreateObject("VBScript.RegExp")
If strPattern <> "" Then
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.test(strInput) Then
Set matches = regEx.Execute(strInput)
result = ""
For Each match In matches
If match.SubMatches.Count > 0 Then
For Each subMatch In match.SubMatches
If Len(result) > 0 Then
result = result & "||"
End If
result = result & subMatch
Next subMatch
End If
Next match
regExSearch = result
Else
regExSearch = "err_nomatch"
End If
End If
Set regEx = Nothing
End Function
Важно открыть файл *.fm в виде текстового файла (.Type = 2) и установить кодировку "utf-8". В противном случае у меня не будет простого текста для регулярного выражения для чтения.
Большое спасибо за то, что привели меня на правильный путь!
Просто сохраните файл FM как MIF. Это текстовая кодировка FM-файла, которую можно конвертировать туда и обратно без потери информации.