Что нового

StringRegExp , Замена фрагментов строки по шаблону

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Просьба помочь разобраться как выполнить замену совпадающих с шаблоном фрагментов строки

В строке : Образец|Опера|Север|Образ|Запад|Восток|Образа

нужно заменить все фрагменты совпадающие со словом : '"Образ"
на слово : "Шаблон" т.е.

получить строку : Шаблон|Опера|Север|Шаблон|Запад|Восток|Шаблон
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
Это делается с помощью функции
Код:
StringRegExpReplace()
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Suppir , спасибо
Suppir сказал(а):
Это делается с помощью функции
Код:
StringRegExpReplace()
Это я знаю , но не могу составить шаблон из-за повторяющихся символов "|"
Ктому же надо найти и заменить весь фрагмент по его части . Фрагмент может находиться в начале слова ,в середине или в конце.
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
Вот так не работает?

Код:
$Text = StringRegExpReplace($Text, "[^|$\s](.*?[Оо]браз.*?)[\|$\s]", $1)


*? - это минимальный квантификатор. Будет искать "0 или более любых символов до ближайшего символа | или конца строки или пробельного символа"

Вообще, для экспериментов с регексами рекомендую Regex Coach(бесплатная) или RegexBuddy (платная).
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Suppir сказал(а):
Вот так не работает?Код: AutoIt [Выделить]$Text = StringRegExpReplace($Text, "[^|$\s](.*?Образ.*?)[\|$\s]", $1)
Нет выдает : ШаблонШаблон

Suppir сказал(а):
Вообще, для экспериментов с регексами рекомендую Regex Coach(бесплатная) или RegexBuddy (платная).
Я пользую самопальный StringRegExTester



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

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

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Код:
$Text = 'Образец|Опера|Север|Образ|Запад|Восток|Образа'
$pattern = 'Образ'
$replace = 'Шаблон'
$aText = StringSplit($Text, '|')
For $i = 1 to $aText[0]
	If StringInStr($aText[$i], $pattern) Then $aText[$i] = $replace
Next
$Text = ''
For $i = 1 to $aText[0] - 1
	$Text &= $aText[$i] & '|'
Next
$Text &= $aText[$aText[0]]
MsgBox(0, '', $Text)
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Kaster, спасибо.
Так можно , но это не очень красиво.И достаточно долго при большом кол-ве строк.
Да и в порядке изучения рег. выражений хотелось бы понять как это сделать
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
Вот, смотри:

http://img137.yfrog.com/i/45233425.png/

Работает, если у "образ" нет префикса, но окончания распознает легко

В разделе "заменить" последняя палка - это активный курсор :smile:

В общем, регулярка выглядит так: ([Оо]браз.*?)(\||$)
или даже так: [Оо]браз.*?(\||$)

Замена выглядит так: Шаблон\2
или так: Шаблон$2

Там внизу сразу видно результат реплейса.


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

В принципе, можно ловить окончания от "образ" (например, образов) и приклеивать к "шаблон" (шаблонов), если нужно
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Suppir сказал(а):
Работает, если у "образ" нет префикса, но окончания распознает легко
Во первых такой шаблон не обработает Фрагмент ,находящийся в начале строки
А если надо найти не Образ а , раз ?
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
gregaz [?]
Во первых такой шаблон не обработает Фрагмент ,находящийся в начале строки

да нет, все прекрасно обработает и в начале строки:
http://yfrog.com/eb84751357p



А если надо найти не Образ а , раз ?

немножко не понял вопрос.
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Ничего не могу понять ?
На тестере получаю :
ШаблонОбразОпера|ШаблонОбразОпера|Север|ШаблонОбразЗапад|Восток|Образа

Вживую получаю :
Код:
$sStr='Образ|Опера|Образ|Опера|Север|Образ|Запад|Восток|Образа'
ConsoleWrite(StringRegExpReplace($sStr, "([Оо]браз.*?)(\||$)", 'Шаблон\1') & @CRLF)
; Полученный результат :   
ШаблонОбразОпера|ШаблонОбразОпера|Север|ШаблонОбразЗапад|Восток|ШаблонОбраза


Suppir Как у тебя получается ??? Можешь проверить вживую код ?

Suppir сказал(а):
немножко не понял вопрос.
Я имел ввиду Проводить поиск по части слова "Образ" : "раз"


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

У тебя же стоит ключ "g" на рисунке . Что это ?
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
gregaz [?]
ConsoleWrite(StringRegExpReplace($sStr, "([Оо]браз.*?)(\||$)", 'Шаблон\1') & @CRLF)

Еще раз посчитай количество сохраняющих скобок :smile:
Мы сохраняем в скобку $1 данные о разделителе. Если ты сохранил в скобку "образ" (что в принципе не нужно делать), то данные о разделителе будут во второй скобке. Сделай как на моем последнем скриншоте.



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

gregaz [?]
У тебя же стоит ключ "g" на рисунке . Что это ?

Глобальный поиск. Т.е. будет находить много совпадений. Первое совпадение на скриншоте выделено желтым, последующие - зеленым. В AutoIt в реплейсе глобальный поиск включен по умолчанию.

В AutoIt для регулярных выражений используется движок PCRE. Эти выражения аналогичны Perl. Советую книжку Фридла по рег. выражениям поискать. Там все очень подробно расписано.
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Suppir сказал(а):
Еще раз посчитай количество сохраняющих скобок
Похоже разобрались.
Да вроде так получается верно :
Код:
$sStr='Образ|Опера|Образ|Опера|Север|Образец|Запад|Восток|Образа'
ConsoleWrite(StringRegExpReplace($sStr, "[Оо]браз.*?(\||$)", 'Шаблон$1')&  @CRLF)
; Полученный результат :   Шаблон|Опера|Шаблон|Опера|Север|Шаблон|Запад|Восток|Шаблон


Теперь бы сделать для более общего случая :
Код:
$sStr='Образ|Опера|Образ|Опера|Север|Образец|Запад|Восток|Образа'
ConsoleWrite(StringRegExpReplace($sStr, "(\||^).*?раз.*?(\||$)", '$1Шаблон$2')&  @CRLF)
; Полученный результат :   Шаблон|Опера|Шаблон|Опера|Шаблон|Запад|Шаблон
НЕ ВЕРЕН
 

r35p3ct

Продвинутый
Сообщения
228
Репутация
60
Код:
$sStr='Образец|Опера|Север|Образ|Запад|Восток|Образа'
$a=StringRegExpReplace($sStr, "(Образ(ец|а)?)", 'Шаблон')
ConsoleWrite( $sStr& @CRLF)
;Шаблон|Опера|Север|Шаблон|Запад|Восток|Шаблон
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
r35p3ct,спасибо.
Но ты похоже не понял задачу.
Это же просто тестовая строка и окончания могут быть другими.
Я пытаюсь создать шаблон для замены всех фрагментов строки ,находящимися между разделителями '|' ( а также в начале и конце строки) ,совпадающих с заданным текстом .
Для текста , находящегося в начале фрагмента (Образ) мы получили рабочий Рег выражение :
Код:
StringRegExpReplace($sStr, "[Оо]браз.*?(\||$)", 'Шаблон$1')

Теперь надо сделать это для общего случая , когда заданный текст не находится в начале фрагмента т.е.
"раз" или "браз" или "бра" и т.п.
 

amel27

Продвинутый
Сообщения
146
Репутация
55
Код:
$f = "браз"
$t = "Шаблон"
$s = "Образец|Опера|Север|Образ|Запад|Восток|Образа"
$r = "(^|\|)([^|]*?"& $f &"[^|]*)"

ConsoleWrite( StringRegExpReplace($s, $r, "$1"& $t) &@CRLF)
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Похоже получил вроде то,что надо :
Код:
$sStr='Образ|Опера|Образ|Опера|Север|Образец|Запад|Восток|Образа'
ConsoleWrite(StringRegExpReplace($sStr, "[^\|]*раз[^\|]*", 'Шаблон')&  @CRLF)
; Полученный результат :   Шаблон|Опера|Шаблон|Опера|Север|Шаблон|Запад|Восток|Шаблон


И код простой и понятный.




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

amel27 , спасибо

Помоему у меня получился еще проще код , не знаю насколько он корректен - надо погонять его .
 

amel27

Продвинутый
Сообщения
146
Репутация
55
gregaz сказал(а):
И код простой и понятный.

Согласен, мой отличается от твоего только наличием якорных символов в начале шаблона - их обычно ставят для ускорения обработки, но для разбора коротких строк это некритично (тем более, что в AutoIT куча времени уходит на предкомпиляцию самого выражения)
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Окончательное решение :
Код:
$f = "бра"
$t = "Шаблон"
$s = "Образец|Опера|Север|Образ|Запад|Восток|Образа"
;$r ="[^\|]*" & $f & "[^\|]*"
$r ="[^|]*" & $f & "[^|]*"
ConsoleWrite( StringRegExpReplace($s, $r, $t) &@CRLF)

Возникает несколько вопросов :
1. Насколько оно оптимально ?
2. Каков логический смысл присутствия символов " * " (мне малопонятна их необходимость,хотя без них -не работает) ?
 

amel27

Продвинутый
Сообщения
146
Репутация
55
gregaz сказал(а):
1. Насколько оно оптимально ?
2. Каков логический смысл присутствия символов " * " (мне малопонятна их необходимость,хотя без них -не работает) ?

1. ИМХО вполне, можно немного оптимизировать:

Код:
$r ="[^|]*" & $f & "[^|]*+"


...только нужно помнить, что $f не просто строка (литера), а регулярное выражение и это можно использовать... например, отключить учёт регистра:

Код:
$f = "[Бб][Рр][Аа]"


2. * - любое количество символов заданного класса ([^|]), без него шаблон будет обозначать: обязательное наличие ОДНОГО символа заданного класса (не разделитель) ПЕРЕД и ПОСЛЕ заданного фрагмента - вот этот кусок и будет заменен.
 
Верх