Что нового

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

Medic84

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

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

Norm

Чайник
Сообщения
17
Репутация
0
Таб, для наглядности я обозначил как \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 499
Репутация
317
Таб, для наглядности я обозначил как \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

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

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

Medic84

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

Norm

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

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

ZaRaki

Новичок
Сообщения
43
Репутация
17
Для автора почти 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

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

ZaRaki

Новичок
Сообщения
43
Репутация
17
Ну хз, помоему ты придераешься ))
Код работает быстро, естественно мощность компа сильно влияет на это.
Например: файл, 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

Скриптер
Сообщения
463
Репутация
121
добавляет два не нужных элемента
Если вы хотите использовать флаг 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
Сообщения
76
Репутация
5
Это обычный 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

Чайник
Сообщения
17
Репутация
0
Лучще б я сюда сегодня не заглядывал :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/
 
Последнее редактирование:
Верх