Что нового

Как быстро разбить на массив строк большой файл, прочитанный целиком?

Medic84

Омега
Команда форума
Администратор
Сообщения
1 561
Репутация
330
@Norm тэг для оформления кода здесь:

Снимок экрана 2019-08-12 в 20.45.42.png
 
  • Like
Реакции: Norm

Norm

Новичок
Сообщения
56
Репутация
1
Таб, для наглядности я обозначил как \t
Содержание строк может быть и другим, но разделители всегда не изменны: \t для столбцов и \n для строк

Код:
Alarm (Feuer/TAL)     \t     Grp. 16 bis Grp. 16    \t    Stg. 4033; LED HLPT 3.UG
Alarm (Feuer/TAL)     \t     Grp. 16 bis Grp. 16    \t     Stg. 4040; LED HLPT
Alarm (Feuer/TAL)     \t    Grp. 16 bis Grp. 16     \t    Stg. 4077; LED HLPT Melder SD
Alarm (Feuer/TAL)     \t    Grp. 16 bis Grp. 17     \t    Stg. 41; SAA Räumung 3.UG
Alarm (Feuer/TAL)     \t    Grp. 16 bis Grp. 44     \t    Stg. 12; Sammelfeuer an GLT
Alarm (Feuer/TAL)     \t    Grp. 16 bis Grp. 44     \t    Stg. 15; Drehkreuzabschaltung
Alarm (Feuer/TAL)     \t    Grp. 16 bis Grp. 44     \t    Stg. 17; Druckbelüftung
Alarm (Feuer/TAL)     \t    Grp. 16 bis Grp. 44     \t    Stg. 18; Lüftungsabschaltung
 
Последнее редактирование модератором:

Medic84

Омега
Команда форума
Администратор
Сообщения
1 561
Репутация
330
Таб, для наглядности я обозначил как \t
Содержание строк может быть и другим, но разделители всегда не изменны: \t для столбцов и \n для строк
Код:
#include <Array.au3>

$sChars = FileRead(@ScriptDir & "\1.txt")
$str = StringRegExp($sChars, "(.*?)\t(.*?)\t(.*)", 4)

For $i = 0 To Ubound($str) - 1
    _ArrayDisplay($str[$i])
Next
 

Norm

Новичок
Сообщения
56
Репутация
1
Мне кажется что это что-то не то.
Построковое считывание это не ускорит, если файл состоит из 50000 строк.
Когда я читал справку, то пологал, что есть возможноть получить , массив массивов за один проход с помощью StringRegExp, тем более, что делает она это быстрее чем Split
Возвращает массив массивов всех совпадений; каждый массив содержит в первом элементе полное совпадение с шаблоном, последующие элементы - совпадение указанных групп (стиль Perl / PHP).
Исходя из этого хотел построить что-то типа такого
Код:
$str=StringRegExp($sChars,"((.*?)\t(.*?)\t(.*)[^\v]+)",4)

Этот код не правилный, я его в качестве примера привел.
Это [^\v]+ четко отделяет строки
Это [^\t]+ отделяет столбцы
Но это только одномерные массивы, а вот как ММ[x][x] сделать используя эти два выражения я не пойму.
Точнее получаются ММ, но они кривые, либо не хватает чего-то либо излишние элементы присутствуют
Вот что выдает указанный выше код
 

Medic84

Омега
Команда форума
Администратор
Сообщения
1 561
Репутация
330
Но это только одномерные массивы, а вот как ММ[x][x] сделать используя эти два выражения я не пойму.
Такой двумерный массив как вы хотите Вы не сделаете через RegExp. Вы можете поделить файл на строки через StringSplit, и потом обрабатывать массив.
 
  • Like
Реакции: Norm

Norm

Новичок
Сообщения
56
Репутация
1
На первой странице этой темы уже похожее обсуждалось, в связи с ограничениями у StringSplit
Кроме того в моем самом первом коде RegExp (с флагом 3) проделывает тоже самое чутка быстрее чем StringSplit
Сначала делит на троки с помощью [^\v]+, а затем дробит строку через [^\t]+
Однако с флагом 4 всё делается за один проход и получается ММ, и всё в два раза быстрее но к сожалению немного не такой размерности.
Вот этот ММ добавляет два не нужных элемента в ММ
Код:
$str=StringRegExp($sChars,"((.*?)\t(.*?)\t(.*)[^\v]+)",4)

В моей таблице должно например быть так $aArr [ 100 ] [ 3 ], а в реальности на выходе имею $aArr [ 100 ] [ 5 ]
Я не могу понять, где в функции RegExp (если стоит флаг 4) "граница" между выражениями для столбцов и строк?
 
Последнее редактирование:

ZaRaki

Знающий
Сообщения
48
Репутация
19
Для автора почти 10 летней давности
Код:
#include <File.au3>
#include <Array.au3>

local $array1[0]
local $array2[0]

$hFile = FileOpen("new.txt")

While 1
    $sLine = FileReadLine($hFile)
    If @error = -1 Then ExitLoop

    $str_spl = stringsplit($sLine,'=')
    _arrayadd($array1,$str_spl[1])
    _arrayadd($array2,$str_spl[2])
WEnd

_ArrayDisplay($array1)
_ArrayDisplay($array2)
FileClose($hFile)

Для Norm из приведённого им примера выше по посту
Код:
#include <File.au3>
#include <Array.au3>

local $array1[0]

$hFile = FileOpen("new.txt")

While 1
    $sLine = FileReadLine($hFile)
    If @error = -1 Then ExitLoop

    $str_spl = stringsplit($sLine,'делиметр')
    _arrayadd($array1,$str_spl[2])
WEnd

_ArrayDisplay($array1)
FileClose($hFile)
 
Последнее редактирование:
  • Like
Реакции: Norm

Norm

Новичок
Сообщения
56
Репутация
1
Спасибо, всем кто откликнулся, но если не получается решить мой вопрос более "изящным" способом, а именно через RerExp то не стоит это дальше продолжать,
Через Split и постоковое чтение получается медленнее чем с RerExp. из моего первого поста.
Так что останусь пока на том что уже есть.
 

ZaRaki

Знающий
Сообщения
48
Репутация
19
Ну хз, помоему ты придераешься ))
Код работает быстро, естественно мощность компа сильно влияет на это.
Например: файл, 73000 строк общим числом в 3.5 миллиона символов, где нет ни 1 лишнего символа и каждый из которого обрабатывается и используется в нужном месте (реальный пример, на примере моего парсера)
Я прогоняю файл через этот код
.
Код:
$file_fulltxt = fileread($file_istochnik)
$main_arr_spl = stringsplit($file_fulltxt,"|==|",1)

local $arr_cats[1] = ['ыы']

for $kkk = 3 to 9 step 2
$datas_spl = stringsplit($main_arr_spl[$kkk],"----------",1)
for $jjj = 1 to $datas_spl[0]
;~ for $jjj = 1 to 4
   $child_datas_spl = stringsplit($datas_spl[$jjj],"=||=",1)

   $iUnixTime1 = _GetUnixTime()*1000
   $random_dir_numb = random(100000000,999999999,1)
   $dirpathimgs = @ScriptDir & "\inetgetfiles\" & $iUnixTime1 & "=" & $random_dir_numb
   DirCreate($dirpathimgs)

   $line_item_imgs_val = ''
   $line_item_imgs = stringsplit($child_datas_spl[1],"|",1)
   for $uuu = 1 to $line_item_imgs[0]
      if (stringlen($line_item_imgs[$uuu]) > 5) then
         $line_item_imgs_spl = stringsplit($line_item_imgs[$uuu],'"',1)
         $line_item_imgs_format = stringsplit($line_item_imgs_spl[2],'.',1)
         filewriteline($file_inetgets, &&&&&&&&&&&&&&&&&&&&&)
         $line_item_imgs_val = $line_item_imgs_val & 'files/' & $iUnixTime1 & "=" & $random_dir_numb & '/' & $uuu & '.' & $line_item_imgs_format[2]
         if ($uuu <> $line_item_imgs[0]) then $line_item_imgs_val = $line_item_imgs_val & '|'
      EndIf
   Next

   $line_item_categor = StringRegExpReplace($child_datas_spl[2],'\d','')
   $line_item_categor = $main_arr_spl[$kkk-1] & '==' & $line_item_categor
   $line_item_categor = StringRegExpReplace($line_item_categor,'\s','@@')

   $line_item_name = $child_datas_spl[3]

   $line_item_opis = $child_datas_spl[4]

   $line_item_cena = StringReplace($child_datas_spl[5],'₽','')
   $line_item_cena = StringRegExpReplace($line_item_cena,'\s{1,}','')

   $line_item_count = $child_datas_spl[6]

   $line_item_location = $child_datas_spl[7]

   filewriteline($file_sqlzaprs, &&&&&&&&&&&&&&&&")

   $arr_searchcat = _arraysearch($arr_cats, $line_item_categor)
   if $arr_searchcat = -1 then
      _arrayadd($arr_cats, $line_item_categor)
      filewriteline($file_sqlzaprs, $line_item_categor)
   EndIf
next
next

.
Как ты заметил там аж 3 цикла, причём цикл в цикле в цикле, 3 сплита, 1 в другом, несколько реплейсов, 3 filewriteline и куча всего другого по мелочи.
Всё вот это, с учётом просто огроменного файла повторю в 3.5 МИЛЛИОНА символа - выполняется за 7 секунд, куда уж быстрее да и смысл быстрее? :smile:
 
  • Like
Реакции: Norm

Tempo

Скриптер
Сообщения
528
Репутация
163
добавляет два не нужных элемента
Если вы хотите использовать флаг 4 и вам нужен массив массивов тогда читайте справку об "лишних элементах"
Возвращает массив массивов всех совпадений; каждый массив содержит в первом элементе полное совпадение с шаблоном, последующие элементы - совпадение указанных групп (стиль Perl / PHP).
То есть при переборе элементов начинайте итерацию с первого элемента
Код:
;~ AutoIt Version: 3.3.14.5
#include <StringConstants.au3>
Local $sData = _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 16" & @TAB & "Stg. 4033; LED HLPT 3.UG" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 16" & @TAB & "Stg. 4040; LED HLPT" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 16" & @TAB & "Stg. 4077; LED HLPT Melder SD" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 17" & @TAB & "Stg. 41; SAA Räumung 3.UG" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 44" & @TAB & "Stg. 12; Sammelfeuer an GLT" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 44" & @TAB & "Stg. 15; Drehkreuzabschaltung" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 44" & @TAB & "Stg. 17; Druckbelüftung" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 44" & @TAB & "Stg. 18; Lüftungsabschaltung"

Local $aRegExp = StringRegExp($sData, "(.*?)\t(.*?)\t(.*)", $STR_REGEXPARRAYGLOBALFULLMATCH)
If @error Then Exit @error

Local $aSubRegExp, $sOut
For $i = 0 To UBound($aRegExp) - 1
    $aSubRegExp = $aRegExp[$i]
    $sOut = ""
    For $j = 1 To UBound($aSubRegExp) - 1
        $sOut &= StringFormat("%i. %s\r\n", $j, $aSubRegExp[$j])
    Next
    MsgBox(0, "Пример перебора " & $i, $sOut)
Next
Если нужен двумерный массив просто отформатируйте результат как вам нужно, например
Код:
;~ AutoIt Version: 3.3.14.5
#include <StringConstants.au3>
#include <Debug.au3>
Local $sData = _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 16" & @TAB & "Stg. 4033; LED HLPT 3.UG" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 16" & @TAB & "Stg. 4040; LED HLPT" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 16" & @TAB & "Stg. 4077; LED HLPT Melder SD" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 17" & @TAB & "Stg. 41; SAA Räumung 3.UG" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 44" & @TAB & "Stg. 12; Sammelfeuer an GLT" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 44" & @TAB & "Stg. 15; Drehkreuzabschaltung" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 44" & @TAB & "Stg. 17; Druckbelüftung" & @CRLF & _
        "Alarm (Feuer/TAL)" & @TAB & "Grp. 16 bis Grp. 44" & @TAB & "Stg. 18; Lüftungsabschaltung"

Local $aRegExp = StringRegExp($sData, "(.*?)\t(.*?)\t(.*)", $STR_REGEXPARRAYGLOBALFULLMATCH)
If @error Then Exit @error

Local $aSubRegExp, $iRows = UBound($aRegExp), $iCols = UBound($aRegExp[0]) - 1, $aOut[$iRows][$iCols]
For $i = 0 To $iRows - 1
    $aSubRegExp = $aRegExp[$i]
    For $j = 1 To $iCols
        $aOut[$i][$j - 1] = $aSubRegExp[$j]
    Next
Next
_DebugArrayDisplay($aOut)


И как уже сказали
Я вот это вот все прочитал, но так и не понял в чем вопрос.
Если хотите что бы вам помогли, советую писать по существу, выкладывать код который хотя бы запускается, использовать Tidy и Best coding practices для минимальной читабельности
 
Последнее редактирование:
  • Like
Реакции: Norm

IMStrelcov

CTPEJIbLLOB
Сообщения
109
Репутация
15
Это обычный CSV-файл ноторый я сначала разбиваю на строки, а потом но столбцы (разделитель TAB)
Пример CSV-файла можно?
Сообщение автоматически объединено:

Код:
$sChars = 'Alarm (Feuer/TAL)                    Grp. 16 bis Grp. 16            Stg. 4033; LED HLPT 3.UG'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 16            Stg. 4040; LED HLPT'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 16            Stg. 4077; LED HLPT Melder SD'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 17            Stg. 41; SAA Raumung 3.UG'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 44            Stg. 12; Sammelfeuer an GLT'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 44            Stg. 15; Drehkreuzabschaltung'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 44            Stg. 17; Druckbeluftung'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 44            Stg. 18; Luftungsabschaltung'&@CRLF

$str=StringRegExp($sChars,"([^\t]*)(?:\t*([^\t]*)\t*)(?:\t*([^\n]*)\n)",3)
If Not @error Then
    $AllNum = UBound($str)/3
    For $a=0 To UBound($str)-3 Step 3
        MsgBox(0,'Строка '& ($a+3)/3 & '/'& $AllNum, $str[$a]&@CRLF&$str[$a+1]&@CRLF&$str[$a+2])
    Next
EndIf
Сообщение автоматически объединено:

Код:
$sChars = 'Alarm (Feuer/TAL)                    Grp. 16 bis Grp. 16            Stg. 4033; LED HLPT 3.UG'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 16            Stg. 4040; LED HLPT'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 16            Stg. 4077; LED HLPT Melder SD'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 17            Stg. 41; SAA Raumung 3.UG'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 44            Stg. 12; Sammelfeuer an GLT'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 44            Stg. 15; Drehkreuzabschaltung'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 44            Stg. 17; Druckbeluftung'&@CRLF
$sChars &= 'Alarm (Feuer/TAL)                Grp. 16 bis Grp. 44            Stg. 18; Luftungsabschaltung'&@CRLF

$str=StringRegExp($sChars,"(?:([^\t]*)(?:\t*([^\t]*)\t*)(?:\t*([^\n]*)\n))",4)
If Not @error Then
    $AllNum = UBound($str)
    For $a=0 To UBound($str)-1
        $tmp = $str[$a]
        MsgBox(0,'Строка '& ($a+1) & '/'& $AllNum, $tmp[1]&@CRLF&$tmp[2]&@CRLF&$tmp[3])
    Next
EndIf
 
Последнее редактирование:
  • Like
Реакции: Norm

Norm

Новичок
Сообщения
56
Репутация
1
Лучще б я сюда сегодня не заглядывал :smile:

Ну хз, помоему ты придераешься ))
Даже и не хотел, зачем мне это.
Так что Вы правы, и Ваш код работает тоже очень быстро.

Если вы хотите использовать флаг 4 и вам нужен массив массивов тогда читайте справку об "лишних элементах"
Конечно читал, но формулировку наверное не сразу понял. Лишь сегодня после Вашего сообщения ещё пару раз внимательно прочел и вслед за Вами проверил код от Tempo, который в точности подтвердил это.
У него массив состоял из полной первой строки (в полном виде) и остальные уже разделенные столбцы.
Но код от ZaRaki сработал на порядок быстрее, чем RegExp
Вот в немецкой справке нашел нормальный пример, с нормальным объяснением, почему флаг 4 никто по сути не использует.
Перевод сказал(а):
К сожалению, вы не можете напрямую обращаться к массивам в массивах "& @CRLF & _
«(не кэшируя их), поэтому я всегда использую флаг 3 вместо флага 4». & @CRLF & _
«Вот все массивы в $ aFlag4:»)

Если хотите что бы вам помогли, советую писать по существу, выкладывать код который хотя бы запускается, использовать Tidy и Best coding practices для минимальной читабельности
Ну так я вроде все и расписал.
Кстати это было мое первое сообщение на форуме, и я пока толком не знал как код вставить, но спасибо Модераторам, всё показали.
Я начал на Autoit писать всего три дня назад, а Вы хотите что всё и сразу. Так не бывает.

Пример CSV-файла можно?
Проверил Ваш код всё прекрасно работает, но я ошибался по поводу возможностей данной функции, применительно к моему случаю.

P.S.
Ещё раз спасибо всем за помощь, разъяснения и примеры.
Надеюсь, что теперь всё успокоится в теме.

Вот ещё может кому-то пригодится, уже готовые решения для превращения CSV в массив:
http://forum.ru-board.com/topic.cgi?forum=5&topic=29240&start=2345
https://geekquestion.com/12751099-kak-prochitat-format-fajla-testcsv-v-autoit/
https://www.autoitscript.com/forum/topic/155748-csvsplit/
 
Последнее редактирование:

Norm

Новичок
Сообщения
56
Репутация
1
Не стал создавать новую тему, поскольку вопрос так же про создание массива из прочитанного файла.

Я всё продолжаю пытаться самостоятельно разбираться этом искустве, но всё никак, особенно StringRegExp с флагом 4 ( $STR_REGEXPARRAYGLOBALFULLMATCH )

Есть меленькие тексты такого типа
Не буду показывать в виде кода, проще будет цветами обозначить
Код:
Steuerung abschalten
Angewendet auf: Steuergruppe 15; RWA Haupttreppe
Auslösung: Meldergruppe 99; Abschaltung St.Gr.15 u.16.......................................... gehend

Gruppe/Melder aus (Эта строка всегда разная и она нужна целиком)
Angewendet auf: Meldergruppe 4016/1; Aktivirung Revision (на этом месте всегда разные текст, но всегда есть \d{1,4}/?\d{1,2}; после этого, текста может и не быть)
Auslösung: Meldergruppe 4015; Revision/Akustik/ÜE-ab .......................................... kommend (на этом месте всегда стоит слово kommend или gehend)
(В текстте тожк всегда есть \d{1,4}/?\d{1,2}; после этого, текста может и не быть)

Чертвм цветом обозначено всё что нужно оставить
Всё что красное или следует дальше после этих строк не нужно
Все красные строки всегда стоят на этих местах и всегда имеют одинаковый текст


На выходе должно быть так:
Gruppe/Melder aus | Meldergruppe 4016/1; Aktivirung Revision | Meldergruppe 4015; Revision/Akustik/ÜE-ab | kommend
Посмотрите пожалуйста мой паттерн
Код:
StringRegExp($aSchalt,"(?im)^.+?$(?:\h?\R^Angewendet auf:\h).+d{1,4}/?\d{1,2};.+?(?:\h\R^Auslösung:\h) ).+d{1,4}/?\d{1,2};.+?(?:\.{4,})(kommend|gehend)", 4)

Сообщение автоматически объединено:

Решил попробовать по иному через StrinrRegExpReplace вычистить всё не нужное.
Получилось в общем-то как и мне нужно, вот только концовку отрезать не получается никак.
Код:
Local $sDat = FileRead("SFunc.txt")
Local $aSchalt = StringRegExpReplace($sDat,"\RAngewendet auf:\h(.+?\d{1,4}/?\d{1,2}?;\h.*?)\h*\RAuslösung:\h(.+?\d{1,4}/?\d{1,2}?;\h.*?)\h?\.{2,}\h?(kommend|gehend)(\h?\R?.*?)",';"\1";"\2";\3'& @CRLF)
MsgBox(0,0,$aSchalt)

На всякий случай прикрепил сам текстовый файл


Уже разобрался, к сожалению это за один проход не убрать, поскольку никак не вписывается в это регулярное выражение.
 
Последнее редактирование:

ra4o

Скриптер
Сообщения
996
Репутация
184
Это обычный CSV-файл ноторый я сначала разбиваю на строки, а потом но столбцы (разделитель TAB)
При помощи Excel не устроит ?
Код:
#include <excel.au3>
#include <array.au3>

$oExcel=_Excel_Open(False)
$oWorkbook=_Excel_BookOpen($oExcel,@ScriptDir&'\1.csv')
$aRange=_Excel_RangeRead($oWorkbook)
_ArrayDisplay($aRange)
 

Norm

Новичок
Сообщения
56
Репутация
1
При помощи Excel не устроит ?
Если речь о более раннем вопросе, то там я уже более менее разобрался и прибегать к помощи Excel только усложнит, кроме того, может оказаться, что Excel не будет под рукой.
 
Верх