|
|||||||
Извлечение таблиц из pdf (в excel), прив. w/vba
Время создания: 31.07.2019 22:37
Раздел: Разные закладки - VBA
Запись: xintrea/mytetra_db_adgaver_new/master/base/1523183464v9kbdgqmdi/text.html на raw.githubusercontent.com
|
|||||||
|
|||||||
Извлечение таблиц из pdf (в excel), прив. w/vba Я пытаюсь извлечь таблицы из pdf файлов с помощью vba и экспортировать их в excel. Если все работает так, как должно, оно должно идти автоматически. Проблема в том, что таблица не стандартизирована. Это то, что у меня есть до сих пор.
И код: With New Scripting.FileSystemObject With .OpenTextFile(strFileName, 1, False, 0) If Not .AtEndOfStream Then .SkipLine Do Until .AtEndOfStream //do something Loop End With End With Все это прекрасно работает. Но теперь я сталкиваюсь с проблемой извлечения таблиц из текстовых файлов.То, что я пытаюсь сделать, это VBA, чтобы найти строку, например. "Year Income", а затем вывести данные после него в столбцы. (Пока таблица не закончится.) Первая часть не очень сложна (найдите определенную строку), но как бы я обошел вторую часть. Текстовый файл будет выглядеть как этот Pastebin . Проблема в том, что текст не стандартизирован. Таким образом, например, некоторые таблицы имеют 3-летние столбцы (2010 2011 2012), а некоторые только две (или 1), некоторые таблицы имеют больше пробелов между столбцом, а некоторые не включают определенные строки (такие как Capital Asset, net). Я думал о том, чтобы делать что-то подобное, но не уверен, как это сделать в VBA.
Я основывал свою первую версию на Pdf, чтобы преуспеть , но чтение онлайн-людей не рекомендуется OpenFile, а скорее FileSystemObject (хотя это, кажется, намного медленнее). Любые указатели, чтобы начать меня, главным образом на шаге 2? 2 ответов
У вас есть несколько способов проанализировать текстовый файл и в зависимости от того, насколько сложно это может привести к тому, что вы опираетесь так или иначе. Я начал это, и он немного вышел из рук... наслаждайтесь. На основе предоставленного вами примера и дополнительных комментариев я отметил следующее. Некоторые из них могут хорошо работать для простых файлов, но могут стать неудобными с более сложными файлами. Кроме того, могут быть несколько более эффективные методы или трюки к тому, что я использовал здесь, но это, безусловно, поможет вам достичь желаемого результата. Надеюсь, это имеет смысл в сочетании с предоставленным кодом:
Следующий код будет извлекать детали активов из текстового файла, вы можете модифицировать его для извлечения других разделов. Он должен обрабатывать несколько строк. Надеюсь, я прокомментировал это достаточно. Посмотрите, и я отредактирую, если вам нужно помочь. Sub ReadInTextFile() Dim fs As Scripting.FileSystemObject, fsFile As Scripting.TextStream Dim sFileName As String, sLine As String, vYears As Variant Dim iNoColumns As Integer, ii As Integer, iCount As Integer Dim bIsTable As Boolean, bIsAssets As Boolean, bIsLiabilities As Boolean, bIsNetAssets As Boolean Set fs = CreateObject("Scripting.FileSystemObject") sFileName = "G:\Sample.txt" Set fsFile = fs.OpenTextFile(sFileName, 1, False) 'Loop through the file as you've already done Do While fsFile.AtEndOfStream <> True 'Determine flag positions in text file sLine = fsFile.Readline Debug.Print VBA.Len(sLine) 'Always skip empty lines (including single spaceS) If VBA.Len(sLine) > 1 Then 'We've found a new table so we can reset the booleans If VBA.InStr(1, sLine, "Table") > 0 Then bIsTable = True bIsAssets = False bIsNetAssets = False bIsLiabilities = False iNoColumns = 0 End If 'Perhaps you want to also have some sort of way to designate that a table has finished. Like so If VBA.Instr(1, sLine, "Some text that designates the end of the table") Then bIsTable = False End If 'If we're in the table section then we want to read in the data If bIsTable Then 'Check for your different sections. You could make this constant if your text file allowed it. If VBA.InStr(1, sLine, "Assets") > 0 And VBA.InStr(1, sLine, "Net") = 0 Then bIsAssets = True: bIsLiabilities = False: bIsNetAssets = False If VBA.InStr(1, sLine, "Liabilities") > 0 Then bIsAssets = False: bIsLiabilities = True: bIsNetAssets = False If VBA.InStr(1, sLine, "Net Assests") > 0 Then bIsAssets = True: bIsLiabilities = False: bIsNetAssets = True 'If we haven't triggered any of these booleans then we're at the column headings If Not bIsAssets And Not bIsLiabilities And Not bIsNetAssets And VBA.InStr(1, sLine, "Table") = 0 Then 'Trim the current line to remove leading and trailing spaces then use the split function to determine the number of years vYears = VBA.Split(VBA.Trim$(sLine), " ") For ii = LBound(vYears) To UBound(vYears) If VBA.Len(vYears(ii)) > 0 Then iNoColumns = iNoColumns + 1 Next ii 'Now we can redefine some variables to hold the information (you'll want to redim after you've collected the info) ReDim sAssets(1 To iNoColumns + 1, 1 To 100) As String ReDim iColumns(1 To iNoColumns) As Integer Else If bIsAssets Then 'Skip the heading line If Not VBA.Trim$(sLine) = "Assets" Then 'Increment the counter iCount = iCount + 1 'If iCount reaches it limit you'll have to redim preseve you sAssets array (I'll leave this to you) If iCount > 99 Then 'You'll find other posts on stackoverflow to do this End If 'This will happen on the first row, it'll happen everytime you 'hit a $ sign but you could code to only do so the first time If VBA.InStr(1, sLine, "$") > 0 Then iColumns(1) = VBA.InStr(1, sLine, "$") For ii = 2 To iNoColumns 'We need to start at the next character across iColumns(ii) = VBA.InStr(iColumns(ii - 1) + 1, sLine, "$") Next ii End If 'The first part (the name) is simply up to the $ sign (trimmed of spaces) sAssets(1, iCount) = VBA.Trim$(VBA.Mid$(sLine, 1, iColumns(1) - 1)) For ii = 2 To iNoColumns 'Then we can loop around for the rest sAssets(ii, iCount) = VBA.Trim$(VBA.Mid$(sLine, iColumns(ii) + 1, iColumns(ii) - iColumns(ii - 1))) Next ii 'Now do the last column If VBA.Len(sLine) > iColumns(iNoColumns) Then sAssets(iNoColumns + 1, iCount) = VBA.Trim$(VBA.Right$(sLine, VBA.Len(sLine) - iColumns(iNoColumns))) End If Else 'Reset the counter iCount = 0 End If End If End If End If End If Loop 'Clean up fsFile.Close Set fsFile = Nothing Set fs = Nothing End Sub
Я не могу проверить образцы данных, поскольку PasteBin был удален. Основываясь на том, что я могу почерпнуть из описания проблемы, мне кажется, что использование регулярных выражений упростит анализ данных. Добавьте ссылку на скрипт Runtime scrrun.dll для FileSystemObject. Создайте экземпляр объекта RegEx с помощью Dim objRE As New RegExp Задайте для свойства Pattern значение "(\ bd {4}\b) {1,3}" Вышеупомянутый шаблон должен соответствовать строкам, содержащим строки, такие как:20102010 20112010 2011 2012 Число пробелов между строками года не имеет значения, если существует хотя бы один (поскольку мы не ожидаем, что будем сталкиваться с такими строками, как 201020112012) Установите для свойства Global значение True Захваченные группы будут найдены в отдельных объектах Match из MatchCollection, возвращенных методом Execute объекта OBRERE объекта RegEx. Поэтому объявите соответствующие объекты: Dim objMatches as MatchCollection Dim objMatch as Match Dim intMatchCount 'tells you how many year strings were found, if any Предполагая, что вы создали объект FileSystemObject и просматриваете текстовый файл, считывая каждую строку в переменной strLine Первый тест, чтобы увидеть, содержит ли текущая строка искомый шаблон: If objRE.Test(strLine) Then 'do something Else 'skip over this line End If Set objMatches = objRe.Execute(strLine) intMatchCount = objMatches.Count For i = 0 To intMatchCount - 1 'processing code such as writing the years as column headings in Excel Set objMatch = objMatches(i) e.g. ActiveCell.Value = objMatch.Value 'subsequent lines beneath the line containing the year strings should 'have the amounts, which may be captured in a similar fashion using an 'additional RegExp object and a Pattern such as "(\b\d+\b){1,3}" for 'whole numbers or "(\b\d+\.\d+\b){1,3}" for floats. For currency, you 'can use "(\b\$\d+\.\d{2}\b){1,3}" Next i Это всего лишь приблизительная схема того, как я подхожу к этой проблеме. Я надеюсь, что в этом коде есть что-то, что поможет вам. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|