Что нового

[RegExp] Замена значения с добавлением символов после и перед значением

wisenlucky

Новичок
Сообщения
36
Репутация
0
Добрый день,

К сожалению не смог найти похожей задачи по поиску. Не помог и мануал.
Есть массив полученный с помощью StringRegExp:

[0]|Price 110,5
[1]|Price 110.5 and 119.5
[2]|Price 118
[3]|Price 119.5 and 133.5

Если в массиве присутствует слово "and", то нужно найти средню между значениями идущими до и после слова "and".

Тоесть на выходе должно получиться:

[0]|Price 110.5
[1]|Price 115
[2]|Price 118
[3]|Price 126.5

Если рассчет в RegExp производить нельзя, как хотя бы добавть скобки перед предыдущим и последующим значением? И можно существуют ли подобные шаблоны вообще?

К своему удивлению не смог найти функцию рассчета средней.
В таком случае нужно поменять "and" на "+", и если присутствует "and" добавть "(" перед предшествующей цифрой и ")/2" после следующего после "and" значения.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Скрипт на 90% состоит из 2-го примера в справке http://autoit-script.ru/autoit3_docs/functions/StringRegExpReplace.htm

Код:
Local $sInput = '|Price 110,5'&@CRLF&'[1]|Price 110.5 and 119.5'&@CRLF&'[2]|Price 118'&@CRLF&'[3]|Price 119.5 and 133.5'

Local $sOutput = StringRegExpReplace($sInput, '(\d+\.?\,?\d+) and (\d+\.?\,?\d+)', '($1+$2)/2' )

Display($sInput, $sOutput)

Func Display($sInput, $sOutput)
    ; Форматированный результат.
    Local $sMsg = StringFormat("Исходный текст:\t%s\n\nРезультат:\t%s", $sInput, $sOutput)
    MsgBox(4096, "Результат", $sMsg)
EndFunc





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

Сам понимаю что не фонтан, но я ж в регулярных выражениях дуб дубом.
Никак не могу написать шаблон для группы - цифры + '.' + ','
 
Автор
W

wisenlucky

Новичок
Сообщения
36
Репутация
0
Спасибо!

Разбираюсь с RegExp уже третий день. Второй пример в справке даже запускал, чтобы посмотреть результат. Но так и не понял, что это то, что нужно. Специфические понятия, нужно привыкнуть. :smile:


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

А подобный рассчет в принципе возможен? Или это уже вопрос другой темы?

Кстати запятая там не обязательна. Я могу заменить её точкой на предыдущем шаге.
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Вариант:
Код:
Local $sInput = '|Price 110,5'&@CRLF&'[1]|Price 110.5 and 119.5'&@CRLF&'[2]|Price 118'&@CRLF&'[3]|Price 119.5 and 133.5'
$aRes=StringRegExp( $sInput, '([\d\.]+\h*and\h*[\d\.]+)', 3 )

For $i=0 To UBound($aRes)-1	
	$sRes =Execute(StringRegExpReplace( $aRes[$i], '([\d\.]+)\h*and\h*([\d\.]+)', '(\1+\2)/2' ))
	MsgBox(4096, "Результат строки : " & $i, $aRes[$i] & " = " & $sRes, 1)
Next


В принципе первые две строчки и не нужны, ведь вроде первичный массив уже есть
 
Автор
W

wisenlucky

Новичок
Сообщения
36
Репутация
0
Спасибо, с шаблонами разобрался! :ok: Несколько дополнительных вопросов по задаче.

1. Иногда цены встречаются со знаком минус и плюс. Я думал, что шаблон
Код:
'(\1+\2)/2)'

будет работать в любом случае.
к примеру((-118)+(-2))/2 посчитается.
По факту вместо рассчета возвращеется: True.
Как можно решить эту проблему? Я пытался подставить скобки, но не помогло.


2. Задачу поставить новые значения обратно в массив я решил следующим образом:
Код:
Local $sInput = '|Price 110,5'&@CRLF&'[1]|Price 110.5 and 119.5'&@CRLF&'[2]|Price 118'&@CRLF&'[3]|Price 119.5 and 133.5'
$aRes=StringRegExp( $sInput, '([\d\.]+\h*and\h*[\d\.]+)', 3 )
 
For $i=0 To UBound($aRes)-1
    $sRes =Execute(StringRegExpReplace( $aRes[$i], '([\d\.]+)\h*and\h*([\d\.]+)', '(\(1)+\(2))/2' ))
    _ArrayAdd($aRes,$sRes)
                ;MsgBox(4096, "????????? ?????? : " & $i, $aRes[$i] & " = " & $sRes, 1)
Next
  For $i=0 To UBound($aRes)/2-1
   _ArrayDelete($aRes,1)
   Next
   _ArrayDisplay($aRes)

Может есть какое-то более элегантное решение для замены старых значений в массиве новыми данными?
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
wisenlucky [?]
к примеру((-118)+(-2))/2 посчитается.
По факту вместо рассчета возвращеется: True.
Как можно решить эту проблему?
Почему ? Все считается. Надо "-" учитывать в рег.выр.
Код:
#include<Array.au3>

Dim $aString[4]=['Price 110,5','Price -110.5 and -119.5', 'Price 118', 'Price 119.5 and 133.5']  
_ArrayDisplay($aString, "$aRes")		
	
$sRes=''
For $i=0 to UBound($aString)-1 
    $s=StringRegExpReplace( $aString[$i], '\D*\s([\d\.-]+)\h*and\h*([\d\.-]+)', '(\1+\2)/2' )
	If @extended=0 Then ContinueLoop
	ConsoleWrite("$s = " & $s & @CRLF)
	$sRes &="$Res= " & Execute($s) &@CRLF
Next
ConsoleWrite($sRes & @CRLF)




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

wisenlucky [?]
Может есть какое-то более элегантное решение для замены старых значений в массиве новыми данными?
На элегантность не потянет, но очень просто :
Код:
#include<Array.au3>

Dim $aString[4]=['Price 110,5','Price -110.5 and -119.5', 'Price 118', 'Price 119.5 and 133.5']  
_ArrayDisplay($aString, "$aString")		

For $i=0 to UBound($aString)-1 
    $s=StringRegExpReplace( $aString[$i], '\D*\s([\d\.-]+)\h*and\h*([\d\.-]+)', '(\1+\2)/2' )
    If @extended=0 Then ContinueLoop
    $aString[$i]=Execute($s)
Next
_ArrayDisplay($aString, "$aResult")

Возможно я не совсем понял что надо иметь на выходе. уж больно просто.
Если заменить в массиве все посчитанные элементы их рез-татом, то так.
Если надо удалять несчитаемые, то лучше по ходу создавать новый массив, а в конце заменить им исходный.
Покажи пример выходного массива.
 
Автор
W

wisenlucky

Новичок
Сообщения
36
Репутация
0
C минусом теперь тоже всё ясно :ok:

На выходе должен получиться вот такой массив. Тоесть первое слово + рассчет.
Код:
[0]|Price 110.5
[1]|Price 115
[2]|Price 118 
[3]|Price 126.5


В твоем примере получается, что где происходит рассчет - слово перед рассчитанными данными стирается. Тоесть получается так:

Код:
[0]|Price 110.5
[1]|115
[2]|Price 118 
[3]|126.5


По моей логике - это можно исправить так, что из полученного массива удалить все первые слова. А потом добавить первой строчкой во все строки удаленное слово. Или есть техника удачнее?


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

Ураа! Заработало! :laugh:
Добавил вот такую строчку в последний код:
Код:
$p=StringRegExp($aString[1],'(?m)(.+?\w)\W',1)

И поменял
Код:
$aString[$i]=Execute($s)
на
Код:
$aString[$i]=$p[0]&" "&Execute($s)

В итоге получился вот такой код:
Код:
#include <Array.au3>

Dim $aString[4]=['Price 110,5','Price -110.5 and -119.5', 'Price 118', 'Price 119.5 and 133.5']  
_ArrayDisplay($aString)
$p=StringRegExp($aString[1],'(?m)(.+?\w)\W',1)
For $i=0 to UBound($aString)-1 
    $s=StringRegExpReplace( $aString[$i], '\D*\s([\d\.-]+)\h*and\h*([\d\.-]+)', '(\1+\2)/2' )
	
    If @extended=0 Then ContinueLoop
    $aString[$i]=$p[0]&" "&Execute($s)
Next
_ArrayDisplay($aString, "$aResult")


Спасибо ещё раз! :IL_AutoIt_1:
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Можно и так , если есть уверенность, что слово одно и тоже (или надо оставить одно и то же), но корректней все таки искать слово имеющееся в каждом исследуемом элементе массива , т.е.
Код:
For $i=0 to UBound($aString)-1 
    $p=StringRegExp($aString[$i],'^([^-\d\.]+)',1)
	$s=StringRegExpReplace( $aString[$i], '^[^-\d\.]+([\d\.-]+)\h*and\h*([\d\.-]+)', '(\1+\2)/2' )
    
    If @extended=0 Then ContinueLoop
    $aString[$i]=$p[0]&" "&Execute($s)
Next


или так :
Код:
For $i=0 to UBound($aString)-1 
	$s=StringRegExpReplace( $aString[$i], '[^-\d\.]+([\d\.-]+)\h*and\h*([\d\.-]+)', '(\1+\2)/2' )
    If @extended=0 Then ContinueLoop
	$aString[$i]=StringRegExpReplace( $aString[$i], '^([^-\d\.]+)[-\d\.].+$', '${1}' & Execute($s) )
Next


Кстати последние выражения корректно определят и в случае : Price119.5 and 133.5 (без пробела)
 
Автор
W

wisenlucky

Новичок
Сообщения
36
Репутация
0
Последний вариант - вообще отлично! :ok: :beer:
 
Верх