Что нового

[RegExp] Получение повторяющейся строки в отдельные элементы массива

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
Пытаюсь получить повторяющейся строки в отдельные элементы массива, на данный момент приходится делать дополнительную обработку чтобы разделить результат, вот что пытался:

Код:
$vTest = _
	'some other data' & @CRLF & _
	'<div class=test>' & @CRLF & _
	'<div class="item-box">test 1</div>' & @CRLF & _
	'<div class="item-box">test 2</div>' & @CRLF & _
	'</div>' & @CRLF & _
	'some other data'

$sParent_Div_Pttrn = '<div class=test>'
$sSub_Div_Pttrn = '(?:<div class="item-box">.*?</div>|\s*)?'
$sGet_Div_Pttrn = '(<div class="item-box">.*?</div>)'
$sClose_Div_Pttrn = '</div>'

$sPattern = '(?is)' & $sParent_Div_Pttrn & $sSub_Div_Pttrn & $sGet_Div_Pttrn & $sSub_Div_Pttrn & $sClose_Div_Pttrn

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)

For $i = 0 To UBound($aRet) - 1
	ConsoleWrite($aRet[$i] & @LF & '--------------' & @LF)
Next


На выходе хотелось бы получить это:
Код:
<div class="item-box">test 1</div>
--------------
<div class="item-box">test 2</div>
--------------
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
Для простоты понимания:

Код:
$vTest = _
	'some other data' & @CRLF & _
	'<div class=test>' & @CRLF & _
	'test1' & @CRLF & _
	'test2' & @CRLF & _
	'</div>' & @CRLF & _
	'some other data'

$sPattern = '(?i)\r\n<div class=test>\r\n(?:(test\d)\r\ntest\d|test\d\r\n(test\d))\r\n</div>\r\n'

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)

For $i = 0 To UBound($aRet) - 1
	ConsoleWrite($aRet[$i] & @LF & '--------------' & @LF)
Next


Но вот интересно, в группе оба условия совпадают, но почему возвращает только первое?
Нужно как то повторять условность...

Или вот ещё пример:

Код:
$vTest = _
	'some other data' & @CRLF & _
	'<div class=test>' & @CRLF & _
	'<div class=item>test1</div>' & @CRLF & _
	'<div class=item>test2</div>' & @CRLF & _
	'</div>' & @CRLF & _
	'some other data'

$sDiv_Pttrn = '<div class=item>test\d</div>'
$sPattern = '(?i)\r\n<div class=test>\r\n(?:' & $sDiv_Pttrn & '\r\n)?(' & $sDiv_Pttrn & ')(?:\r\n' & $sDiv_Pttrn & ')?\r\n</div>\r\n'

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)

For $i = 0 To UBound($aRet) - 1
	ConsoleWrite($aRet[$i] & @LF & '----------------' & @LF)
Next
 

edyapd

Осваивающий
Сообщения
380
Репутация
30
Не уверен, что правильно понял условие, так как входные строки разные. Но как-то так:
Код:
$vTest = _
    'some other data' & @CRLF & _
    '<div class=test>' & @CRLF & _
    '<div class="item-box">test 1</div>' & @CRLF & _
    '<div class="item-box">test 2</div>' & @CRLF & _
    '</div>' & @CRLF & _
    'some other data'
	
;~ $vTest = _
;~     'some other data' & @CRLF & _
;~     '<div class=test>' & @CRLF & _
;~     'test1' & @CRLF & _
;~     'test2' & @CRLF & _
;~     '</div>' & @CRLF & _
;~     'some other data'

$sPattern = '<div class="item-box">test \d<\/div>' ; Для первой строки
;$sPattern = '(?i)test\d'							;Для второй строки

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)

For $i = 0 To UBound($aRet) - 1
    ConsoleWrite($aRet[$i] & @LF & '--------------' & @LF)
Next
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
edyapd [?]
Не уверен, что правильно понял условие
Обязательно условие, это содержание этих строк внутри тега div с классом test.

Пример где это не сработает:

Код:
$vTest = _
    'some other data' & @CRLF & _
    '<div class=test>' & @CRLF & _
    '<div class="item-box">test 1</div>' & @CRLF & _
    '<div class="item-box">test 2</div>' & @CRLF & _
    '</div>' & @CRLF & _
    'some other data' & @CRLF & _
	'<div class=test2>' & @CRLF & _
    '<div class="item-box">test 3</div>' & @CRLF & _
    '<div class="item-box">test 4</div>' & @CRLF & _
    '</div>' & @CRLF & _
    'some other data'

$sPattern = '<div class="item-box">test \d</div>'

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)

For $i = 0 To UBound($aRet) - 1
    ConsoleWrite($aRet[$i] & @LF & '--------------' & @LF)
Next


Тут мне нужно только test 1 и test 2.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Обязательно условие, это содержание этих строк внутри тега div с классом test.
Та это понятно.

Непонятно как вот эти данные могут попасть в результат.
Код:
$vTest = _
    'some other data' & @CRLF & _
    '<div class=test>' & @CRLF & _
    'test1' & @CRLF & _
    'test2' & @CRLF & _
    '</div>' & @CRLF & _
    'some other data'
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
Вроде получилось, не знаю как, но оно работает:

Код:
$vTest = _
	'some other data' & @CRLF & _
	'<div class=test>' & @CRLF & _
	'<div class=item>test1</div>' & @CRLF & _
	'<div class=item>test2</div>' & @CRLF & _
	'<div class=item>test3</div>' & @CRLF & _
	'</div>' & @CRLF & _
	'some other data' & @CRLF & _
	'<div class=test1>' & @CRLF & _
	'<div class=item>test4</div>' & @CRLF & _
	'<div class=item>test5</div>' & @CRLF & _
	'<div class=item>test6</div>' & @CRLF & _
	'</div>' & @CRLF & _
	'some other data'

$sParent_Open = '<div class=test>\s*'
$sParent_Close = '</div>'
$sDiv = '<div class=item>.*?</div>'
$sPattern = '(?si)(?:' & $sParent_Open & '(' & $sDiv & ')\s*)(' & $sDiv & ')\s*(?:(' & $sDiv & ')\s*' & $sParent_Close & '\s*)'

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)

For $i = 0 To UBound($aRet) - 1
	ConsoleWrite($aRet[$i] & @LF & '----------------' & @LF)
Next
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
Рано я обрадовался, шаблон (его структура) тот же, но вот так уже не работает:

Код:
$vTest = _
	'</div>' & @CRLF & _
	'<div class="test">' & @CRLF & _
	'<div class="item-box">data1</div>' & @CRLF & _
	'<div class="item-box">data2</div>' & @CRLF & _
	'<div class="item-box">data3</div>' & @CRLF & _
	'<div class="item-box">data4</div>' & @CRLF & _
	'<div class="item-box">data5</div>' & @CRLF & _
	'</div>' & @CRLF & _
	'<div class="test1">' & @CRLF & _
	'<div class="item-box">data6</div>' & @CRLF & _
	'</div>'

$sParent_Open = '<div class="test">\s*'
$sParent_Close = '</div>'
$sDiv = '<div class="item-box">.*?</div>'
$sPattern = '(?si)(?:' & $sParent_Open & '(' & $sDiv & ')\s*)(' & $sDiv & ')\s*(?:(' & $sDiv & ')\s*' & $sParent_Close & '\s*)'

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)

For $i = 0 To UBound($aRet) - 1
	ConsoleWrite($aRet[$i] & @LF & '----------------' & @LF)
Next


Последние 3 элемента попадают в одну ячейку массива.
 

Redline

AutoIT Гуру
Сообщения
506
Репутация
375
Думаю не выйдет решить данную проблему одной регуляркой. (Буду рад, если меня кто-то поправит).
Мне пока не доводилось видеть таких выражений, которые бы учитывали внешний тэг, и захватывали то что внутри.
Здесь было уже несколько похожих тем. В одной из таких вы даже сами отвечали ;)
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
CreatoR,
А не легче решить этот вопрос с помощью объекта HTMLFILE, или Вам нужно только регуляркой?
 

edyapd

Осваивающий
Сообщения
380
Репутация
30
Не знаю, может кто сможет это в одно объеденить. У меня пока мозгов не хватает. Хотя допускаю, что это возможно сделать.
Код:
$vTest = _
    '</div>' & @CRLF & _
    '<div class="test">' & @CRLF & _
    '<div class="item-box">data1</div>' & @CRLF & _
    '<div class="item-box">data2</div>' & @CRLF & _
    '<div class="item-box">data3</div>' & @CRLF & _
    '<div class="item-box">data4</div>' & @CRLF & _
    '<div class="item-box">data5</div>' & @CRLF & _
    '</div>' & @CRLF & _
    '<div class="test1">' & @CRLF & _
    '<div class="item-box">data6</div>' & @CRLF & _
    '</div>'


$sDiv = '<div class="item-box">.*?</div>'
$sPattern = '(?is)(?:<div class="test">\s*)(.*?)(?=\s+</div>)'
$sPattern1 = '(?is)(' & $sDiv & ')'

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)
$aRet = StringRegExp($aRet[0], $sPattern1, 3)

For $i = 0 To UBound($aRet) - 1
    ConsoleWrite($aRet[$i] & @LF & '--------------' & @LF)
Next

И ещё, меняются условия то <div class=test>, то <div class="test">. Ну и содержание test - data
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
Redline [?]
Здесь было уже несколько похожих тем. В одной из таких вы даже сами отвечали
Забыл :whistle:.

madmasles [?]
А не легче решить этот вопрос с помощью объекта HTMLFILE
Легче, но я лично не доверяю объектам, это может быть отключено в системе.

Мне нужно одним выражением, двумя не подходит, я уже используя два.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Так что ли? Но одной регуляркой вы тут не обойдетесь. Вы хотите получить N элементов массива используя конечное число захватываемых групп, а такое нельзя сделать.
Код:
#include <array.au3>
$vTest = _
    '</div>' & @CRLF & _
    '<div class="test">' & @CRLF & _
    '<div class="item-box">data1</div>' & @CRLF & _
    '<div class="item-box">data2</div>' & @CRLF & _
    '<div class="item-box">data3</div>' & @CRLF & _
    '<div class="item-box">data4</div>' & @CRLF & _
    '<div class="item-box">data5</div>' & @CRLF & _
    '</div>' & @CRLF & _
    '<div class="test1">' & @CRLF & _
    '<div class="item-box">data6</div>' & @CRLF & _
    '</div>'

$pattern = '(?smi)<div class="test">\R(.*<div class="item-box">data\d</div>)(?1)'
$aArray = StringRegExp($vTest, $pattern, 3)
$a2 = StringSplit($aArray[0],@CRLF, 1)
_ArrayDisplay($a2)
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
inververs [?]
одной регуляркой вы тут не обойдетесь
Если бы я в этом был уверен, то не стал бы создавать тему.

Я на 99% уверен что это можно сделать одним выражением.
Логика примерно такая:

Искать подстроку, перед которой обязательно находится другая строка, после которой может быть такая же искомая подстрока (не обязательно), и после которой обязательно находится другая строка, перед которой может быть такая же искомая подстрока (не обязательно).
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
CreatoR [?]
Искать подстроку, перед которой обязательно находится другая строка, после которой может быть такая же искомая подстрока (не обязательно), и после которой обязательно находится другая строка, перед которой может быть такая же искомая подстрока (не обязательно).
http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags

Используйте лучше HTMLFILE, не встречал систем, где это было бы отключено. :smile:
 

edyapd

Осваивающий
Сообщения
380
Репутация
30
Может так устроит:
Код:
$vTest = _
    '</div>' & @CRLF & _
    '<div class="test">' & @CRLF & _
    '<div class="item-box">data1</div>' & @CRLF & _
    '<div class="item-box">data2</div>' & @CRLF & _
    '<div class="item-box">data3</div>' & @CRLF & _
    '<div class="item-box">data4</div>' & @CRLF & _
    '<div class="item-box">data5</div>' & @CRLF & _
    '</div>' & @CRLF & _
    '<div class="test1">' & @CRLF & _
    '<div class="item-box">data6</div>' & @CRLF & _
    '</div>'

$sDiv = '<div class="item-box">.*?</div>'
$sPattern = '(?is)(?<=<div class="test">\r\n)(.*' & $sDiv & ')(?=.*?<div class="test\d">)'

ConsoleWrite(@LF & '!Pattern: ' & $sPattern & @LF & @LF)
$aRet = StringRegExp($vTest, $sPattern, 3)

For $i = 0 To UBound($aRet) - 1
    ConsoleWrite($aRet[$i] & @LF & '--------------' & @LF)
Next
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
edyapd [?]
Может так устроит:
Это не отличается от предыдущих результатов (всё помещается в один элемент массива).
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
firex [?]
Используйте лучше HTMLFILE, не встречал систем, где это было бы отключено
Да и с ним не так просто работать...
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Код:
$pattern = '(?smi)\G(?:.*?<div class="?test"?>\R*)*?(<div class="?item.*?</div>)\R*'

:beer:
 

sngr

AutoIT Гуру
Сообщения
1,011
Репутация
409
Первый раз вижу боевое применение ключа \G.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,485
C2H5OH
Гениально! :beer:
 
Верх