Что нового

Найти имя в строке параметров, с помощью регулярного выражения

Webarion

Осваивающий
Сообщения
143
Репутация
24
Ребят! Подсобите с регуляркой:

Код:
$sLine = '		module=apps |  	name	 |reload|path=D:\~Приложения 	 | 	cache=0	 	|	 	icon=icon.ico		  |click  '
$key = StringRegExp($sLine,'(?:^|\|)\t*\s*(.+?[^=])\t*\s*(?:\||$)',1)
_P($key); - вместо ConsoleWrite и _ArrayDisplay


Строка состоит из блоков с разделителем |. Нужно найти неизвестное имя, в первом блоке, в котором нет знака =. В начале и в конце любого блока могут быть пробелы и табуляторы. Нужна именно регулярка. В данном примере $key[0] нужно, чтобы было name
 

sngr

AutoIT Гуру
Сообщения
1,010
Репутация
408
Код:
#include 'array.au3'

$sLine = '      module=apps |   name    |reload|path=D:\~Приложения   |  cache=0     |       icon=icon.ico         |click  '
$key = StringRegExp($sLine,'(?:^|\|)([^=\|]+)(?:\||\z)',1)
 _ArrayDisplay($key)
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
Alofa сказал(а):
Интересно, а что формирует строку, программа? Скрипт?
Строку, пока формирует человек. На самом деле, там может быть несколько строк, но это уже детали. Моя хотелка, хочет иметь гибкую штуку, с возможностью не только для скрипта, но и для «коробочки от мозгов» В общем, должно быть так, чтобы, куда ни «плюнь», а всё равно работает.
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Код:
#include 'array.au3'

$sLine = '      module=apps |   name    |reload|path=D:\~Приложения   |  cache=0     |       icon=icon.ico         |click  '
; $key = StringRegExp($sLine,'(?:^|\|)([^=\|]+)(?:\||\z)',1)
$key = StringRegExp($sLine,'(?:\|\h+)([^=\|\s]+)',1)
 ; _ArrayDisplay($key)
 MsgBox(0, 'Сообщение', '|' & $key[0] & '|')
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
Спасибо AZJIO! Вот не знал про \h, оказывается и \s работает так как мне нужно
К сожалению, ваш пример, при перестановке параметров даёт ответ module вместо name:
Код:
$sLine = '   name    |      module=apps |reload|path=D:\~Приложения   |  cache=0     |       icon=icon.ico         |click  '


У меня работает следующая конструкция: (?:^|\|)\s*([^=\|]+?)\s*(?:\||\z) но здесь есть маленький недочёт, если в строке присутствует пустой блок, то он принимается за имя и выдаётся пустой результат, это логично для данной конструкции, но хотелось бы, чтобы пустые блоки пропускались, как будто их нет:
Код:
$sLine = '	 module=mod1	 |	 |	 |	 _(name1)	 |	 name2	 |	 param1=1	 |	 param2=2	 |	 key1	 |	 |	 key2|key3	 '
$key = StringRegExp($sLine,'(?:^|\|)\s*([^=\|]+?)\s*(?:\||\z)',1)
ConsoleWrite( $key[0] )

В этом примере, нужный результат _(name1)




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

Пошла родимая, вот то, что доктор прописал:

Код:
$sLine = '	 module=mod1	 |	 |	 |	 _(name1)	 |	 param1=1	 |	 param2=2	 |	 key1	 |	 |	 key2|key3	 '
$key = StringRegExp($sLine,'(?:^|\|)\s*([^|\s][^=]+?)\s*(?:\||\z)',1)
ConsoleWrite( $key[0] )



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

В конечном итоге, такая вот получилась функция извлечения параметров:

Код:
$sLine = ' module=mod1 | | | `~!@#$%^&()№;%{},-[]_\/?<>+ AZ az АЯ ая | param1 = 1 | param2 = 2 |  param3 = test=1 | 9 | key1 | | key2|key3 '

ConsoleWrite('>>>Строка: ' & $sLine & @CR)
ConsoleWrite('Имя: ' & _getParam($sLine) & @CR) ; по умолчанию получаем имя - первый не пустой блок не содержащий в себе знака равенства
ConsoleWrite('Имя: ' & _getParam($sLine, 'name') & @CR) ; можно и так
ConsoleWrite('Есть ли ключ key2: ' & _getParam($sLine, 'key2') & @CR) ; проверить присутствие ключа
ConsoleWrite('Есть ли ключ key5: ' & _getParam($sLine, 'key5') & @CR) ;
ConsoleWrite('Есть ли ключ 9:    ' & _getParam($sLine, '9') & @CR)
ConsoleWrite('Параметр param2:   ' & _getParam($sLine, 'param2') & @CR) ; получить параметр
ConsoleWrite('Параметр param3:   ' & _getParam($sLine, 'param3') & @CR) ;
ConsoleWrite('Параметр param99:  ' & _getParam($sLine, 'param99') & @CR)

; первое явно указанное имя имеет больший приоритет
$sLine = ' module=mod1 | | | name1 | name = name2 | param1 = 1 | param2 = 2 | key1 | | key2|key3 '
ConsoleWrite('>>>Строка: ' & $sLine & @CR)
ConsoleWrite('Явно указанное имя: ' & _getParam($sLine) & @CR)
; в присутствии явно указанного имени, не явно указанное считается ключом
ConsoleWrite('Есть ли ключ name1: ' & _getParam($sLine, 'name1') & @CR)

; Извлечение по порядковому номеру
ConsoleWrite('>>>Извлечение параметров по порядковому номеру' & @CR)
ConsoleWrite('5-й блок строки: ' & _getParam($sLine, 5) & @CR)
ConsoleWrite('5-й блок, игнорируя пустые: ' & _getParam($sLine, 5, 1) & @CR)
ConsoleWrite('Если блок превышен, то последний: ' & _getParam($sLine, 99) & @CR)
ConsoleWrite('4-й блок с конца строки: ' & _getParam($sLine, -4) & @CR)
ConsoleWrite('4-й блок, с конца, игнорируя пустые: ' & _getParam($sLine, -4, 1) & @CR)
ConsoleWrite('Если блок с конца превышен, то первый: ' & _getParam($sLine, -99) & @CR)


;*****************************************************************************************************
; Извлечение параметра из строки вида: name|param=1|param=2|key1|key2                                ;
; Имя - первый не пустой блок без знака равенства                                                    ;
; Имя можно задать явно name=Имя, тогда любой первый блок без знака равенства будет считаться ключом ;
; Ключ - остальные не пустые блоки без знака равенства                                               ;
; Параметр - блок вида param=val                                                                     ;
;*****************************************************************************************************
Func _getParam($sParams, $sGet = 'name', $sSp = '')

	Local $aKey

	$aKey = StringRegExp($sParams, '(?:^|\|)\s*(?i:' & $sGet & ')\s*=\s*([^\|]*?)\s*(?:\||$)', 1) ; извлекает значение параметра
	If IsArray($aKey) And $aKey[0] Then Return $aKey[0]

	If $sGet = 'name' Then $aKey = StringRegExp($sParams, '(?:^|\|)\s*([^|\s][^=]+?)\s*(?:\||\z)', 1) ; извлекает имя
	If IsArray($aKey) And $aKey[0] Then Return $aKey[0]

	$aKey = StringRegExp($sParams, '(?:^|\|)\s*(' & $sGet & ')\s*(?:\||\z)', 0) ; определяет присутствие ключа
	If $aKey Then Return 1

	If IsNumber($sGet) Then ; извлечение по порядковому номеру
		$sGet -= 1
		If $sSp Then $sSp = '\s' ; если необходимо игнорировать пустые блоки
		$aKey = StringRegExp($sParams, '([^' & $sSp & '\|].*?)\s*(?:\||\z)', 3)
		If IsArray($aKey) And UBound($aKey) > 0 Then
			If $sGet < -1 Then $sGet = UBound($aKey) + $sGet + 1
			If $sGet < 0 Then $sGet = 0
			If $sGet > UBound($aKey) - 1 Then $sGet = UBound($aKey) - 1
			Return $aKey[$sGet]
		EndIf
	EndIf

	Return 0

EndFunc   ;==>_getParam
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Vanguger сказал(а):
К сожалению, ваш пример, при перестановке параметров даёт ответ module вместо name:
А кто-ж знал про перестановку параметров? Тогда нужно парсить по другому - удалить все зарегистрированные параметры, останется только имя.
1. Удалить пробелы прилегающие к разделителю "|"
2. Удалить повтор "|"
3. Сделать StringSplit
4. Проверить каждый параметр на соответствие списку зарегистрированных параметров
5. Оставшийся параметр определить как имя

У тебя 4 параметра без "=", значит если параметры не имеют упорядоченности и могут следовать в любом порядке, то любое вместо name может оказаться захваченным регулярным выражением. А значит твой подход не верен.
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
Так и думал, что так ответишь :smile:

AZJIO сказал(а):
А кто-ж знал про перестановку параметров?
Каюсь, считал, что это понятно исходя из фразы:
Vanguger сказал(а):
Нужно найти неизвестное имя, в первом блоке, в котором нет знака =

На счёт StringSplit я подумаю, если будет быстрее, то почему нет.

AZJIO сказал(а):
Проверить каждый параметр на соответствие списку зарегистрированных параметров

Это я называю жёсткой логикой, часто, это верно, но не в моём случае. Я пробовал это в контексте основного решения на самом начальном этапе, и мне это не подошло. Мне нужно гибче.

AZJIO сказал(а):
У тебя 4 параметра без "=", значит если параметры не имеют упорядоченности и могут следовать в любом порядке, то любое вместо name может оказаться захваченным регулярным выражением. А значит твой подход не верен

Прекрасно тебя понимаю. Но всё же конкретное условие есть, любой первый блок без знака = есть имя, следовательно остальные похожие выполняют другую функциональность. Без этой опоры никак, а иначе, действительно, подход был бы хаотичным и не верным.

Дружище, в любом случае, благодарю за ответ. Я уже показал функцию, которая ещё будет тестироваться на недочёты и дотачиваться, но уже работает так как нужно и в данный момент работает очень хорошо.То есть подход уже верен, только потому, что он хорошо работает и обходит жёсткую привязку к зарегистрированным параметрам. И меня это действительно радует.

Всем спасибо! Тема решена. Но варианты и предложения всё равно рассматриваются :smile:
 
A

Alofa

Гость
Vanguger сказал(а):
... Но варианты и предложения всё равно рассматриваются
Vanguger сказал(а):
... Строку, пока формирует человек...
... и скорее всего это происходит в текстовом файле. Согласитесь, что неопытный юзер когда-нибудь да запутается в формировании столь длинной строки.
Используйте .INI, этим вы облегчите жизнь и пользователям и себе.
 
Автор
W

Webarion

Осваивающий
Сообщения
143
Репутация
24
Так и есть, правда .ini я уже облазил вдоль и поперёк, структуру пытаясь максимально упростить для понимания, но в итоге пришёл к тому, что нужно создать свою, это мне больше понравилось. Да и строка сама по себе не столь длинна, это для тестирования и здесь я разложил её в максимально утрированной форме, столько параметров и не будет, всё просто на самом деле. Но также понимая, что неопытный юзер, это «неопытный юзер», для него пожалуй будет предусмотрен интерфейс, а вот для себя и более продвинутого, желающего создавать свои модули, есть простой и понятный текстовый файл, на основе которого кстати, легко собирается интерфейс. Но до красотулек, я пока не добрался, ещё логика рихтуется.

AZJIO, Alofa, sngr, спасибо за ответы, ваши подсказки ценны и некоторые моменты я обязательно обдумаю. :ok:
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Vanguger [?]
Но варианты и предложения всё равно рассматриваются
Код:
#include 'array.au3'

$sLine = '      module=apps |   name    |reload|path=D:\~Приложения   |  cache=0     |       icon=icon.ico         |click  '
$key = _GetNameParam($sLine)
 _ArrayDisplay($key)
 MsgBox(0, 'Сообщение', '|' & $key[0] & '|')

Func _GetNameParam($sLine)
	Local $tmp
	$tmp = StringRegExpReplace('|' & $sLine & '|','\h*\|\h*', '|') ; удалить пробелы
	$tmp = StringRegExpReplace($tmp,'\|{2,}', '|') ; удалить повторы "|"
	$tmp = StringRegExpReplace($tmp,'\|[^|]+?=[^|]+?(?=\|)', '') ; удалить параметры с "="
	$tmp = StringRegExpReplace($tmp,'\|(reload|click)(?=\|)', '') ; удалить перечисленные параметры
	$tmp = StringTrimLeft($tmp, 1)
	$tmp = StringTrimRight($tmp, 1)
	$tmp = StringSplit($tmp, '|', 2)
	Return $tmp
EndFunc
 
Верх