Личный хомяк Максима

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Личный хомяк Максима » Autoit » Скрипт, шерстящий кучу Excel файла в поисках табличных данных


Скрипт, шерстящий кучу Excel файла в поисках табличных данных

Сообщений 1 страница 2 из 2

1

Написал по просьбе одной милой девушки... )

Инструкция

Итак, программа. Очень простая, не требует никаких особых знаний, но имеет свои ограничения. Ограничения связаны с тем, что ячейки Екселя не обладают жестко заданной структурой, и сделаны следующие допущения:
1) На компе все таки есть Office и Excel...
2) информация извлекается из товарной накладной - это лист "тн " (именно так, с пробелом) в любой найденной книге XLS. Если в книге такого листа нет, то книга пропускается - в общем списке будет предупреждение.
3) информация о товаре находится на три строки ниже слова "товар", расположенного во 2-м столбце, ищется с 15 по 35 строку. Поиск строк с товаром кончается если при переборе строк следующая оказывается пустой. Если же слово "товар" вообще не найдено, то книга тоже пропускается - делается предупреждение.
4) Номер документа находится обязательно в девятом столбце на две ячейки ниже надписи "номер документа", которая находится пределах от 10-й до 30-й строки, т.е. ее расположение по вертикали может "плавать" и программа будет искать ее в этих пределах.
5) Плательщик находится в третьем столбце, на двух строках, и он ищется по слову "Плательщик" в первом или втором столбце, само слово ищется от 5 до 25 строки
6) дата составления находится в десятом столбце, ищется по фразе "Дата составления", плавает от 10 до 30 строки
7) суммарное количество всех строк с товаром не может превышать 10000 - можно поставить и 65 тысяч, это максимум для экселя, но время работы вырастет в разы - объем пустого пространства тоже перемалывается и на это тратится время.

Работа:
1) при запуске программы она спрашивает, в какой файл сохранять данные. Указываем, при необходимости перезаписи существующего файла подтверждаем это
2) указываем директорию, в которой лежат наши рабочие файлы. Там должны лежать ТОЛЬКО файлы, соответствующие вышеприведенным условиям, иначе программа вылетит. Как лежат файлы, в каких подпапках - не важно, она их всех найдет и извлечет данные.
3) получаем сообщение что все ок и все - можно открывать файл с результатом.
4) Раздвиньте колонки по вкусу, выделите все семь (выделив заголовки, если кто не в курсе) и нажмите Данные-Фильтр-Автофильтр - получите простейшую базу данных с фильтрованием по любому параметру или их сочетанию.

Код:
#include <Array.au3>

MsgBox (0, "Предупреждение", "Рекомендую перед работой ознакомиться с инструкцией Excel.txt, ибо программа имеет ограничения, связанные с человеческим фактором")

$oExcel = ObjGet("", "Excel.Application") ; "схватить" существующий объект Excel (например, файл уже открыт в Excel)

If @error Then ; в случае неудачи создаем новый объект Excel и открываем требуемый файл
    $oExcel = ObjCreate("Excel.Application") ; создать объект Excel
    If Not IsObj($oExcel) Then Exit ; выйти, если не удалось создать объект Excel
EndIf

$sFilePath = FileSaveDialog ( "Указать путь к файлу результата", "", "Книга Excel (*.xls)", 1)
$oExcel.Workbooks.Add
$oExcel.ActiveWorkBook.SaveAs ($sFilePath)
$oExcel.ActiveWorkBook.ActiveSheet.Name = "Таблица товаров"

$DirsArray = DirListToArray(StringRegExpReplace(FileSelectFolder( "Папка", "")& "\", '\\[^\\]+$', ''))
;_ArrayDisplay($DirsArray)

$FilesArray = FilesListToArray($DirsArray)
;_ArrayDisplay($FilesArray)
 
$StrArray = DataToList($FilesArray)
;_ArrayDisplay($StrArray)

$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Cells(1, 1) = "Товар"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Cells(1, 2) = "Кол-во"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Cells(1, 3) = "Ед.изм"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Cells(1, 4) = "Дата отправления"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Cells(1, 5) = "Накладная"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Cells(1, 6) = "Покупатель"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Cells(1, 7) = "Цена"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Rows(1).Font.Bold = True

for $i = 1 to $StrArray[0][0]
	for $j = 0 to 6
    $oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица товаров").Cells($i+1, $j+1) = $StrArray[$i][$j]
	Next
Next


$oExcel.DisplayAlerts = 0 ; отключить предупреждения
$oExcel.Save ; сохранить файл
$oExcel.Quit ; выйти из экселя

MsgBox (0, "Поздравляю", "Файл результата готов")

Func DirListToArray($sPath, $sRootPath=1)
    $sPath = StringRegExpReplace($sPath, '\\+$', '')
    Local $aRetArray[1], $aSubDirsArr, $sFindNextFile, $sCurrentPath
 
    Local $sFindFirstFile = FileFindFirstFile($sPath & "\*.*")
    If @error = 1 Then Return SetError(1, 0, -1)
 
    If $sRootPath = 1 Then
        ReDim $aRetArray[2]
        $aRetArray[1] = $sPath
        $aRetArray[0] += 1
    EndIf
 
    While 1
        $sFindNextFile = FileFindNextFile($sFindFirstFile)
        If @error = 1 Then ExitLoop
         $sCurrentPath = $sPath & "\" & $sFindNextFile
         If StringInStr(FileGetAttrib($sCurrentPath), "D") Then
            $aRetArray[0] += 1
            ReDim $aRetArray[$aRetArray[0]+1]
            $aRetArray[$aRetArray[0]] = $sCurrentPath
             $aSubDirsArr = DirListToArray($sCurrentPath, 0)
             If IsArray($aSubDirsArr) Then
                For $i = 1 To $aSubDirsArr[0]
                    $aRetArray[0] += 1
                    ReDim $aRetArray[$aRetArray[0]+1]
                    $aRetArray[$aRetArray[0]] = $aSubDirsArr[$i]
                Next
            EndIf
        EndIf
    WEnd
 
    FileClose($sFindFirstFile)
 
    Return $aRetArray
EndFunc

Func FilesListToArray($sPath, $Ext="xls")

$j = $sPath[0]

for $i = 1 to $j
    Local $sFindFirstFile = FileFindFirstFile($sPath[$i] & "\*." & $Ext)
    If @error = 1 Then Return SetError(1, 0, -1)
;	_ArrayAdd ( $sPath, $sPath[$i] & "\" & $sFindFirstFile ) 

    While 1
        $sFindNextFile = FileFindNextFile($sFindFirstFile)
        If @error = 1 Then ExitLoop
        _ArrayAdd ( $sPath, $sPath[$i] & "\" & $sFindNextFile)
        $sPath[0] += 1

    WEnd
Next

for $i = 1 to $j
	_ArrayDelete ( $sPath, 1)
    $sPath[0] -= 1
Next

    Return $sPath
EndFunc

Func DataToList ($sPath)

Dim $Excels[10000][7]

$i = 0

Do
	$ii=$i + 1

	$oExcel.Workbooks.Open ($sPath[$ii]) ; открыть в Excel указанный файл
	
	if FindSht(RetFileName($sPath[$ii]), "тн ") = True Then
    $str = FindStr(RetFileName($sPath[$ii]), 'Товар', 15, 2)
    if $str > 0 then
    	$dates = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells(FindStr(RetFileName($sPath[$ii]), 'Дата составления', 10, 10)+2, 10).Value
    	$num = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells(FindStr(RetFileName($sPath[$ii]), 'Номер документа', 10, 9)+2, 9).Value
    	$n = FindStr(RetFileName($sPath[$ii]), 'Плательщик:', 5, 1) + FindStr(RetFileName($sPath[$ii]), 'Плательщик:', 5, 2)
    	$pl = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells($n, 3).Value & ' ' & $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells($n + 1, 3).Value
    	$j = 4
    	While $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells($str + $j, 2).Value > ""
        $Excels[0][0] += 1 
        $Excels[$Excels[0][0]][0] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells($str + $j, 2).Value
        $Excels[$Excels[0][0]][1] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells($str + $j, 10).Value
        $Excels[$Excels[0][0]][2] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells($str + $j, 4).Value
        $Excels[$Excels[0][0]][6] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets("тн ").Cells($str + $j, 11).Value
        $Excels[$Excels[0][0]][3] = StringMid( $dates, 7, 2) & '.' & StringMid( $dates, 5, 2) & '.' & StringMid( $dates, 1, 4)
        $Excels[$Excels[0][0]][4] = $num
        $Excels[$Excels[0][0]][5] = $pl
        $j += 1 
    	WEnd
    Else
    	$Excels[0][0] += 1 
    	$Excels[$Excels[0][0]][0] = "Книга " & $sPath[$ii] & " пропущена - не найдены данные"
    EndIf
	Else
    $Excels[0][0] += 1 
    $Excels[$Excels[0][0]][0] = "Книга " & $sPath[$ii] & " пропущена - не найден лист с данными"
	EndIf

	$oExcel.DisplayAlerts = 0 ; отключить предупреждения
	$oExcel.Save ; сохранить файл
	$oExcel.workbooks(RetFileName($sPath[$ii])).Close(0); // xlDontSaveChanges

	$i += 1
Until $i = $sPath[0]

    Return $Excels

EndFunc

Func RetFileName ($var)
    $var2 = StringLen ($var)
	if StringLen ($var) > 0 then Return StringRight( $Var, $var2 - StringInStr( $var, "\", 0, -1 ))
EndFunc

Func RetDirName ($var)
	if StringLen ($var) > 0 then Return StringLeft( $Var, StringInStr( $var, "\", 0, -1 ))
EndFunc

Func FindStr ($sFile, $str, $x, $y)
	for $i = $x to $x + 20
    if StringInStr( $oExcel.Workbooks($sFile).Worksheets("тн ").Cells($i, $y).Value, $str) > 0 then Return $i
	Next
EndFunc

Func FindSht ($sFile, $str)
	$x = False
	$y = $oExcel.Workbooks($sFile).Sheets.Count
	for $i = 1 to $y
    if $oExcel.Workbooks($sFile).Worksheets($i).Name = $str then $x = True
	Next
	Return $x
EndFunc

0

2

Версия скрипта для парсинга таблиц материалов

Инструкция

Итак, программа. Очень простая, не требует никаких особых знаний,
но имеет свои ограничения.

1) На компе все таки есть Office и Excel. Писать свои модули
   обработки файлов лень, поэтому используется уже готовое.
2) информация извлекается из первого листа книги - в каждом файле
   он один и называется по разному - в любой найденной книге XLS.
3) Ищется в строке 13 столбце D слово "BILL OF MATERIAL" - в случае
   его отсутствия файл пропускается и в конечном файле прописывается
   "Книга ххх пропущена - не найдены данные".
4) суммарное количество всех строк с данными не может превышать 10000
   - можно поставить и 65 тысяч, это максимум для экселя, но время
   работы вырастет в разы - объем пустого пространства тоже
   перемалывается и на это тратится время.

Работа:

1) при запуске программы она спрашивает, в какой файл сохранять
   данные. Указываем, при необходимости перезаписи существующего
   файла подтверждаем это
2) указываем директорию, в которой лежат наши рабочие файлы. Там
   должны лежать ТОЛЬКО файлы, соответствующие вышеприведенным
   условиям, иначе программа вылетит. Как лежат файлы, в каких
   подпапках - не важно, она их всех найдет и извлечет данные.
3) получаем сообщение что все ок и все - можно открывать файл с
   результатом.
4) Раздвиньте колонки по вкусу, выделите все десять (выделив
   заголовки, если кто не в курсе) и нажмите Данные-Фильтр-Автофильтр
   - получите простейшую базу данных с фильтрованием по любому
   параметру или их сочетанию.

Код:
#include <Array.au3>

MsgBox (0, "Предупреждение", "Рекомендую перед работой ознакомиться с инструкцией Excel.txt, ибо программа имеет ограничения, связанные с человеческим фактором")

$oExcel = ObjGet("", "Excel.Application") ; "схватить" существующий объект Excel (например, файл уже открыт в Excel)

If @error Then ; в случае неудачи создаем новый объект Excel и открываем требуемый файл
    $oExcel = ObjCreate("Excel.Application") ; создать объект Excel
    If Not IsObj($oExcel) Then Exit ; выйти, если не удалось создать объект Excel
EndIf

$sFilePath = FileSaveDialog ( "Указать путь к файлу результата", "", "Книга Excel (*.xls)", 1)
$oExcel.Workbooks.Add
$oExcel.ActiveWorkBook.SaveAs ($sFilePath)
$oExcel.ActiveWorkBook.ActiveSheet.Name = "Таблица"

$DirsArray = DirListToArray(StringRegExpReplace(FileSelectFolder( "Папка", "")& "\", '\\[^\\]+$', ''))
;_ArrayDisplay($DirsArray)

$FilesArray = FilesListToArray($DirsArray)
;_ArrayDisplay($FilesArray)
 
$StrArray = DataToList($FilesArray)
;_ArrayDisplay($StrArray)

$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 1) = "System:"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 2) = "Pipe Class:"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 3) = "OMK-PLATE"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 4) = "AP"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 5) = "Master No.TBZ"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 6) = "Quantity"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 7) = "Description1"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 8) = "Description2"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 9) = "Description3"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Cells(1, 10) = "Weight Kg"
$oExcel.Workbooks(RetFileName($sFilePath)).Worksheets("Таблица").Rows(1).Font.Bold = True

for $i = 1 to $StrArray[0][0]
	for $j = 0 to 9
    $oExcel.Workbooks(RetFileName($sFilePath)).Worksheets(1).Cells($i+1, $j+1) = $StrArray[$i][$j]
	Next
Next


$oExcel.DisplayAlerts = 0 ; отключить предупреждения
$oExcel.Save ; сохранить файл
$oExcel.Quit ; выйти из экселя

MsgBox (0, "Поздравляю", "Файл результата готов")

Func DirListToArray($sPath, $sRootPath=1)
    $sPath = StringRegExpReplace($sPath, '\\+$', '')
    Local $aRetArray[1], $aSubDirsArr, $sFindNextFile, $sCurrentPath
 
    Local $sFindFirstFile = FileFindFirstFile($sPath & "\*.*")
    If @error = 1 Then Return SetError(1, 0, -1)
 
    If $sRootPath = 1 Then
        ReDim $aRetArray[2]
        $aRetArray[1] = $sPath
        $aRetArray[0] += 1
    EndIf
 
    While 1
        $sFindNextFile = FileFindNextFile($sFindFirstFile)
        If @error = 1 Then ExitLoop
         $sCurrentPath = $sPath & "\" & $sFindNextFile
         If StringInStr(FileGetAttrib($sCurrentPath), "D") Then
            $aRetArray[0] += 1
            ReDim $aRetArray[$aRetArray[0]+1]
            $aRetArray[$aRetArray[0]] = $sCurrentPath
             $aSubDirsArr = DirListToArray($sCurrentPath, 0)
             If IsArray($aSubDirsArr) Then
                For $i = 1 To $aSubDirsArr[0]
                    $aRetArray[0] += 1
                    ReDim $aRetArray[$aRetArray[0]+1]
                    $aRetArray[$aRetArray[0]] = $aSubDirsArr[$i]
                Next
            EndIf
        EndIf
    WEnd
 
    FileClose($sFindFirstFile)
 
    Return $aRetArray
EndFunc

Func FilesListToArray($sPath, $Ext="xls")

$j = $sPath[0]

for $i = 1 to $j
    Local $sFindFirstFile = FileFindFirstFile($sPath[$i] & "\*." & $Ext)
    If @error = 1 Then Return SetError(1, 0, -1)
;	_ArrayAdd ( $sPath, $sPath[$i] & "\" & $sFindFirstFile ) 

    While 1
        $sFindNextFile = FileFindNextFile($sFindFirstFile)
        If @error = 1 Then ExitLoop
        _ArrayAdd ( $sPath, $sPath[$i] & "\" & $sFindNextFile)
        $sPath[0] += 1

    WEnd
Next

for $i = 1 to $j
	_ArrayDelete ( $sPath, 1)
    $sPath[0] -= 1
Next

    Return $sPath
EndFunc

Func DataToList ($sPath)

Dim $Excels[10000][10]

$i = 0

Do
	$ii=$i + 1

	$oExcel.Workbooks.Open ($sPath[$ii]) ; открыть в Excel указанный файл
	
    if StringInStr( $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells(13, 4).Value, "BILL OF MATERIAL") > 0 then
    	$System = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells(8, 5).Value
    	$Pipe = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells(9, 5).Value
    	$OMKPLATE = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells(15, 6).Value
    	$j = 19
    	While $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells($j, 4).Value > ""
        $Excels[0][0] += 1 
        $Excels[$Excels[0][0]][0] = $System
        $Excels[$Excels[0][0]][1] = $Pipe
        $Excels[$Excels[0][0]][2] = $OMKPLATE
        $Excels[$Excels[0][0]][3] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells($j, 1).Value
        $Excels[$Excels[0][0]][4] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells($j, 2).Value
        $Excels[$Excels[0][0]][5] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells($j, 3).Value
        $Excels[$Excels[0][0]][6] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells($j, 4).Value
        $Excels[$Excels[0][0]][7] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells($j, 5).Value
        $Excels[$Excels[0][0]][8] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells($j, 6).Value
        $Excels[$Excels[0][0]][9] = $oExcel.Workbooks(RetFileName($sPath[$ii])).Worksheets(1).Cells($j, 7).Value
        $j += 1 
    	WEnd
    Else
    	$Excels[0][0] += 1 
    	$Excels[$Excels[0][0]][0] = "Книга " & $sPath[$ii] & " пропущена - не найдены данные"
    EndIf

	$oExcel.DisplayAlerts = 0 ; отключить предупреждения
;	$oExcel.Save ; сохранить файл
	$oExcel.workbooks(RetFileName($sPath[$ii])).Close(0); // xlDontSaveChanges

	$i += 1
Until $i = $sPath[0]

    Return $Excels

EndFunc

Func RetFileName ($var)
    $var2 = StringLen ($var)
	if StringLen ($var) > 0 then Return StringRight( $Var, $var2 - StringInStr( $var, "\", 0, -1 ))
EndFunc

Func RetDirName ($var)
	if StringLen ($var) > 0 then Return StringLeft( $Var, StringInStr( $var, "\", 0, -1 ))
EndFunc

Func FindStr ($sFile, $str, $x, $y)
	for $i = $x to $x + 20
    if StringInStr( $oExcel.Workbooks($sFile).Worksheets(1).Cells($i, $y).Value, $str) > 0 then Return $i
	Next
EndFunc

0


Вы здесь » Личный хомяк Максима » Autoit » Скрипт, шерстящий кучу Excel файла в поисках табличных данных