Доброго времени суток, Планетяне! Не думал, что так тупану выручайте
Есть строка, в которой нужно заменить видимые знаки "умножения" (типа буквы "ха" в кириллице и "экс" в латинице) на звёздочку.
То есть шаблон должен быть что-то вроде "(\d)( *)(?=X|x|Х|х)( *)(\d)": • между 2мя цифрами стоит "ха" или "икс" • буквы могут быть в обоих регистрах • могут быть отбиты одним и более пробелами с каждой из сторон или пробелы могцт отсутствовать (совсем или с одной стороны)
Что накалякал
Код
Sub ChangeHA(iVal)
Static RE As RegExp
If RE Is Nothing Then Set RE = New RegExp: RE.Global = True: RE.Pattern = "(\d)( *)(?=X|x|Х|х)( *)(\d)"
iVal = RE.Replace(iVal, $1\*$5)
Exit Sub
Sub Test
Dim txt$
txt="разный текст 10X000 разный текст
разный текст 10 X000 разный текст
разный текст 10X 000 разный текст
разный текст 10 X 000 разный текст
разный текст 10x000 разный текст
разный текст 10 x000 разный текст
разный текст 10x 000 разный текст
разный текст 10x000 разный текст
разный текст 10x000 разный текст
разный текст 10x000 разный текст
разный текст 10x000 разный текст"
ChangeHA txt
MsgBox txt
End Sub
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Sanja, смысл понял - благодарю! Оттестирую и отпишусь. А в каких случаях нужен "?="?. Я читал и подумал, что как раз моё - а оно всё гораздо проще оказалось.
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Дальнейший подбор начинается немедленно, а не после символов, входящих в скобки. НЕ фиксирует подбор в коллекции SubMatces.
Это просто проверка на то, что наш шаблон удовлетворяет условию, что после предшествующих определений в шаблоне идёт именно (?=что-то там). Зажирнённое никогда не входит в результат Match.Value. Использование вне проверки, что заканчивается, по существу бессмысленно. По другому проверка с возвратом что-заканчивается на.. без включения в результат отбора.
Андрей VG, приветствую! Спасибо - редко работаю с ними и поэтому, наверное туго. А как лучше и быстрее (для скорости работы) сделать? Можно ли обойтись без проверки .Test и .Execute, что бы сразу заменить "иксы" на звёздочки одним Replace'ом?
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Public Function RegExpReplace(ByVal Text As String, ByVal Pattern As String, ByVal Replace As String, _
Optional ByVal Glob As Boolean = False, _
Optional ByVal IgnoreCase As Boolean = False, _
Optional ByVal MultiLine As Boolean = False)
Static regex As Object
If regex Is Nothing Then
Set regex = CreateObject("VBScript.RegExp")
End If
regex.Pattern = Pattern
regex.Global = Glob
regex.MultiLine = MultiLine
regex.IgnoreCase = IgnoreCase
RegExpReplace = regex.Replace(Text, Replace)
End Function
Владимир, приветствую! Вы тоже, как всегда, выручаете! Не успел вчера почитать толком про SubMatches, а, в частности, про применение "$" в шаблоне — как оказывается, варианту от Sanja просто не хватило скобок для того, чтобы после обратиться к найденному через "$".
Подошёл вот такой шаблон: "(\d) *[XxХх] *(\d)". IgnorCase убрал, т.к. (вроде) лучше перечислить ещё 2 значка, чем проверять всё, но больше из-за того, что далее в коде могут быть другие шаблоны, а переключать IgnoreCase в цикле я не хочу. \s заменил на пробел символом, т.к. \s - пробельный символ. Эквивалентно [\f\n\r\t\v] и тесты по TrimRE показали, что так хоть и чуточку, но быстрее
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Приветствую! Нагородил в тот раз, так толком и не разобравшись. Прошу помощи ещё раз
Код
Код
Option Explicit
Option Private Module
'====================================================================================================
Private Sub RegExpTester()
Dim RE As New RegExp
Dim x, tx$
tx = "x1x2X3х4ХХ5x" ' должно получиться "x1•2•3•4••5x"
RE.Global = True
RE.Pattern = "(\d)([xXхХ])+(\d)" ' кириллические "ха" и латинские "икс" в разных регистрах
If Not RE.Test(tx) Then Exit Sub
tx = RE.Replace(tx, "$1•$3"): Debug.Print tx ' а получается "x1•2X3•4ХХ5x"
End Sub
хитрость с "(?=\d)[xXхХ](?=\d)" тоже не понял/не удалась
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
JayBhagavan, вообще ничего не понял - у вас получилось? Заменять не вариант, потому что условие "если между 2мя цифрами стоит ха или икс вне зависимости от регистра, то заменить её на жирную центральную точку=СИМВОЛ(149)"
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Option Explicit
Private Sub RegExpTester()
Dim RE As Object
Set RE = CreateObject("VBScript.RegExp")
Dim tx$, txNEW$
Dim objMatches As Object
Dim i As Long
tx = "x1x2X3х4ХХ5x"
RE.Global = True
RE.Pattern = "(^\D\d)|(\d\D$)|(\D)+|(\d)+"
Set objMatches = RE.Execute(tx)
For i = 0 To objMatches.Count - 1
RE.Pattern = "\d+"
If Not RE.Test(objMatches.Item(i).Value) Then
RE.Pattern = "\D"
txNEW = txNEW & RE.Replace(objMatches.Item(i).Value, "•")
Else
txNEW = txNEW & objMatches.Item(i).Value
End If
Next
Debug.Print txNEW
End Sub
JayBhagavan, спасибо, но это слишком костыльно и долго - быстрее тогда уж будет строковыми А вообще мне просто нужно правильно шаблон написать - то есть именно шаблон мне нужен, а не сам результат, т.к. добиться такого результат можно и без регулярок и с шаблоном "$1•$3", но в несколько проходов (Do…Loop) - будет и короче и быстрее
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Private PRegExp As Object
Function ReplaceMultSign(ByVal inText As String) As String
Dim foo
If PRegExp Is Nothing Then
Set PRegExp = CreateObject("VBScript.RegExp")
PRegExp.IgnoreCase = True
PRegExp.Global = True
PRegExp.Pattern = "(\d)( *(?:x|х)+ *)(?=\d)"
End If
Set foo = PRegExp.Execute(inText)
ReplaceMultSign = PRegExp.Replace(inText, "$1 " & ChrW(&H2022) & " ")
End Function
как выкрутить для более одной. Увы, похоже RegExp.Replace нет указания на число повторов, тогда только через SubMatches и пересбор строки, скорее всего.
Андрей VG, как всегда великолепно - огромное спасибо!
Принцип работы (разбор шаблона, как я понял):
1. (\d) — ищем цифру Заключаем в скобки для использования из коллекции SubMatches с помощью $1 - первый элемент 2. ( *(?:x|х)+ *) — после цифры должны идти символы "Ха" или "Икс" .IgnoreCase позволяет указать по одному варианту регистра, а искать по всем Просто перечислить варианты разделителей в квадратных скобках не получится - нужен дополнительный оператор "?:", позволяющий комбинировать варианты 3. (?=\d) — оператор перед цифровым символом указывает, что не нужно добавлять элемент подбор, а просто проверить, что после разделителей идёт цифра
Заменить разделители отдельно не получается, поэтому заменяем цифру из первого подбора вместе с новым разделителем
КОД
Код
Option Explicit
Option Private Module
'====================================================================================================
Private Sub RegExpTester()
Dim RE1 As New RegExp, RE2 As New RegExp
Dim x$, tx$, t!, n&
tx = "Аx1x2X3хxXхХ4ХХ5xA" ' Аx1•2•3•4•5xA
RE1.Global = True: RE1.Pattern = "(\d)( *(?:x|х)+ *)(?=\d)": RE1.IgnoreCase = True
RE2.Global = True: RE2.Pattern = "(\d)( *(?:x|X|х|Х)+ *)(?=\d)"
t = Timer
For n = 1 To 1000000
x = RE1.Replace(tx, "$1•") ' 1.22
' x = RE2.Replace(tx, "$1•") ' 1.43
Next n
Debug.Print Timer - t, x
End Sub
Интересный момент - несмотря, на то, что вместо 2ух символов можно написать 4, но при этом не игнорировать регистр, с игнорированием чуть быстрее
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄