Что нового

StringRegExp , Поиск в файле фрагментов,содержащих специальные символы

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Имеется файл данных ($sFileDat) , содержащий ряд строк вида:

'Menu='Ann|Aleks|Mishel|Maks\'
'Ann=c:\++Folder1\Folder2\Folder3\2.avi'
'Aleks=d:\Folder4\===Folder5\3.avi''
'Mishel=c:\++Folder1\Folder2\Folder3\4.avi'
'Maks=d:\Folder4\===Folder5\5.avi''
........=........................................

Требуется найти массив строк , начинающихся на заданную букву и содержащих заданный фрагмент .
Фрагмент может содержать в себе одну , несколько папок или весь путь (из правой части строки)
Как видим в фрагменте могут присутствовать специальные символы (+,|,\ и т.п.).
Я пытался делать так :
Код:
$sReadFile = FileRead($sFileDat)
;$letter='a'
$letter='m'
;$folder=c:\++Folder1\Folder2\Folder3
$folder='d:\Folder4\===Folder5'
$folder=StringReplace ($folder,'\','\\')
$aFind=StringRegExp($txt, '(?i)(?m)(^'&$letter&'.*[=].*?\+'&$folder&'.*?)$', 3)

но не смог получить результата.
 

beve

Осваивающий
Сообщения
104
Репутация
31
Если бы без StringRegExp(), то можно было так:
Код:
#include <file.au3>
Global $aRecords
Global $BeginLetter="M"
Global  $search="Folder"

If Not _FileReadToArray("file.Txt",$aRecords) Then
   MsgBox(4096,"Error", " Error reading log to Array     error:" & @error)
   Exit
EndIf

For $x = 1 to $aRecords[0]
	If StringLeft($aRecords[$x],2)="'"&$BeginLetter And StringInStr ( $aRecords[$x], $search,1) Then    Msgbox(0,'Line:' & $x, $aRecords[$x])
Next
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gregaz [?]
Требуется найти массив строк , начинающихся на заданную букву и содержащих заданный фрагмент .
Фрагмент может содержать в себе одну , несколько папок или весь путь (из правой части строки)
Как видим в фрагменте могут присутствовать специальные символы (+,|,\ и т.п.).
Код:
#include <Array.au3>

$sReadFile = ClipGet() ;FileRead($sFileDat)
;$letter = 'a'
$letter = 'm'
;$folder = 'c:\++Folder1\Folder2\Folder3'
$folder = 'd:\Folder4\===Folder5'
$aFind = StringRegExp($sReadFile, '(?im)(^.?' & $letter & '.*=.*\Q' & $folder & '\E.*)[\n\r]?', 3)

_ArrayDisplay($aFind)


Так? :scratch:
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
CreatoR [?]
Спасибо . Почти так .
Строка : Menu=Ann|Aleks|Mishel|Maks определяется как : Menu=Ann (до 1-го разделителя).

Для удобства тестирования я запишу исх.данные в виде строковой переменной:
Код:
$a='Menu=Ann|Aleks|Mishel|Maks'
$b='Ann=c:\++Folder1\Folder2\Folder3\2.avi'
$c='Aleks=d:\Folder4\===Folder5\3.avi'
$d='Mishel=c:\++Folder1\Folder2\Folder3\4.avi'
$e='Maks=d:\Folder4\===Folder5\5.avi'
$sString=$a & @crlf & $b & @crlf & $c & @crlf & $d & @crlf & $e

Кстати если можно в 2-х словах о метасимволах \Q и \E



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

Похоже именно \Q отменяет специальные значения символов до момента появления \E (еслит я правильно понимаю)
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gregaz [?]
Строка : Menu=Ann|Aleks|Mishel|Maks определяется как : Menu=Ann (до 1-го разделителя).
Ну об этом небыло ни слова в задаче ;)
И что конкретно нужно искать в такой строке?

если можно в 2-х словах о метасимволах \Q и \E
Для строки попадающей между этими ключами отменяются спец. символы.
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Похоже неверно определяется по 1-й букве для случая :
Код:
#include <Array.au3>

$a='Menu=Ann|Aleks|Mishel|Maks'
$b='Ann=c:\++Folder1\Folder2\Folder3\2.avi'
$c='Aleks=d:\Folder4\===Folder5\3.avi'
$d='Mishel=c:\++Folder1\Folder2\Folder3\4.avi'
$e='Maks=d:\Folder4\===Folder5\5.avi'
$sReadFile=$a & @crlf & $b & @crlf & $c & @crlf & $d & @crlf & $e

$letter = 'a'
$folder = 'd:\Folder4\===Folder5'
;$aFind = StringRegExp($sReadFile, '(?im)(^.?' & $letter & '.*=.*\Q' & $folder & '\E.*)[\n\r]?', 3)
;Может так :
$aFind = StringRegExp($sReadFile, '(?im)(^' & $letter & '.*=.*\Q' & $folder & '\E.*)[\n\r]?', 3)
_ArrayDisplay($aFind)



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


CreatoR сказал(а):
Ну об этом небыло ни слова в задаче И что конкретно нужно искать в такой строке?

Значит невнянто задал задание.
Искать также всю строку:
если есть совпадение в правой части (после знака =) для Ann|Aleks|Mishel|Maks или Ann|Aleks
Если это сильно усложняет задачу может просто добавить исключение строки со словом : Menu


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

И еще как оказалось самое главное : Выражение не хочет работать на реальном файле ???
Одна из причин , оказывается флаг (?i) - флаг независимости от регистра написания работает только для латиницы и соответственно т,к, некоторые папки написаны на кирилице , то происходит неверное сравнение .
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gregaz [?]
Искать также всю строку:
Всё ровно не ясно, что в ней искать? Если фрагмент, то какой?

Одна из причин , оказывается флаг (?i) - флаг независимости от регистра написания работает только для латиницы и соответственно т,к, некоторые папки написаны на кирилице , то происходит неверное сравнение .
Это проблема... но её можно решить так (лешившись сохранения структуры регистра букв в получаемых строках):
Код:
#include <Array.au3>

$sReadFile = _
	'Menu=Ann|Aleks|Mishel|Maks' & @CRLF & _
	'Ann=c:\++Folder1\Folder2\Folder3\2.avi' & @CRLF & _
	'Aleks=d:\Folder Тест 4\===Folder5\3.avi' & @CRLF & _
	'Mishel=c:\++Folder1\Folder2\Folder3\4.avi' & @CRLF & _
	'Maks=d:\Folder4\===Folder5\5.avi'

$hFile = FileOpen(@DesktopDir & "\test.txt", 2)
FileWrite($hFile, $sReadFile)
FileClose($hFile)

$sReadFile = FileRead(@DesktopDir & "\test.txt")

$sLetter = 'a'
$sFragment = 'd:\Folder тест 4\===Folder5'

$aFind = StringRegExp(StringLower($sReadFile), '(?im)(^' & $sLetter & '.*=.*\Q' & StringLower($sFragment) & '\E.*)[\n\r]?', 3)
_ArrayDisplay($aFind)


Ну или можно так, ничего не нарушается, но это длиннее:
Код:
#include <Array.au3>

$sReadFile = _
	'Menu=Ann|Aleks|Mishel|Maks' & @CRLF & _
	'Ann=c:\++Folder1\Folder2\Folder3\2.avi' & @CRLF & _
	'Aleks=d:\Folder тест 4\===Folder5\3.avi' & @CRLF & _
	'Mishel=c:\++Folder1\Folder2\Folder3\4.avi' & @CRLF & _
	'Maks=d:\Folder4\===Folder5\5.avi'

$hFile = FileOpen(@DesktopDir & "\test.txt", 2)
FileWrite($hFile, $sReadFile)
FileClose($hFile)

$sReadFile = FileRead(@DesktopDir & "\test.txt")
$sFragment = StringLower('d:\Folder тест 4\===Folder5')
$sLetter = 'a'

$aSplit_FRead = StringSplit(StringStripCR($sReadFile), @LF)
Dim $aFind[$aSplit_FRead[0]]

For $i = 1 To $aSplit_FRead[0]
	If StringRegExp(StringLower($aSplit_FRead[$i]), '(?im)(^' & $sLetter & '.*=.*\Q' & $sFragment & '\E.*)[\n\r]?') Then
		$aFind[0] += 1
		$aFind[$aFind[0]] = $aSplit_FRead[$i]
	EndIf
Next

ReDim $aFind[$aFind[0]+1]

_ArrayDisplay($aFind)
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
CreatoR, огромное спасибо.
Последний вариант работает так как надо. :IL_AutoIt_1:
Я эту задачу выполнял раньше используя ф-ию : _FileFindText + др.строковые ф-ии.
При большом файле поиск затягивался до 5-6 секунд.
Используя регулярное выражение операция выполняется почти на порядок быстрее.
Заодно пытаюсь изучить их.
Остался один вопрос ?
CreatoR сказал(а):
Всё ровно не ясно, что в ней искать? Если фрагмент, то какой?
Добавим в файл данных строку :
Ann|Aleks|Mishel|Maks=c:\++Folder1\Folder2\Folder3
При поиске фрагмента : c:\++Folder1\Folder2\Folder3 в массив попадает урезанная строка : Ann
Как исключить из полученного массива все строки , содержащие символ '|' (можно ли без использования : If StringInStr ...) ?
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Догадался таки :

Код:
;...............................
;If StringRegExp(StringLower($aSplit_FRead[$i]), '(?im)(^' & $sLetter & '.*=.*\Q' & $sFragment & '\E.*)[\n\r]?') Then
If StringRegExp(StringRegExpReplace(StringLower($aSplit_FRead[$i]),'.*\|.*',''), '(?im)(^' & $sLetter & '.*=.*\Q' & $sFragment & '\E.*)[\n\r]?') Then
;..............................


Насколько корректно и оптимально оно ?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gregaz [?]
При поиске фрагмента : c:\++Folder1\Folder2\Folder3 в массив попадает урезанная строка
На самом деле она не урезанная, это в списке урезается т.к каждая колонка разделяется символом |. Вот доказательсво этому (замени _ArrayDisplay на этот отрезок):

Код:
$sRet = ""

For $i = 1 To $aFind[0]
	$sRet &= $aFind[$i] & @CRLF
Next

MsgBox(64, 'Title', $sRet)
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
CreatoR [?]
На самом деле она не урезанная, это в списке урезается т.к каждая колонка разделяется символом |.
Да это понятно.

Именно поэтому решил исключить все строки с символом | .
Код:
;...............................

If StringRegExp(StringRegExpReplace(StringLower($aSplit_FRead[$i]),'.*\|.*',''), '(?im)(^' & $sLetter & '.*=.*\Q' & $sFragment & '\E.*)[\n\r]?') Then
;..............................

Насколько корректно и оптимально это ?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gregaz [?]
Именно поэтому решил исключить все строки с символом |
Зачем?

Насколько корректно и оптимально это ?
Это будет учитываться при проверке, и зачем тогда замена? Я бы так сделал:

Код:
For $i = 1 To $aSplit_FRead[0]
	$sLine = StringLower($aSplit_FRead[$i])
	$sPattern = '(?im)(^' & $sLetter & '.*=.*\Q' & $sFragment & '\E.*)[\n\r]?'
	
    If StringRegExp($sLine, $sPattern) And Not StringRegExp($sLine, '(?im)^.*\|.*?=') Then
        $aFind[0] += 1
        $aFind[$aFind[0]] = $aSplit_FRead[$i]
    EndIf
Next
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
CreatoR [?]
Это будет учитываться при проверке, и зачем тогда замена? Я бы так сделал:

Да , конечно , так правильней , чем у меня.
Спасибо. Теперь я хоть кое , что понял в рег. выражениях.

На конкретном примере все становится понятнее.
 
Верх