ФОН
Я хочу заменить слова, содержащие только буквы и цифры, а также букву и цифру, пробелами. Я использую VBA, как показано в примере ниже.
Предлагаемое решение смотрите здесь: https://stackoverflow.com/a/7684859
ВОПРОС
Почему регулярное выражение соответствует слову «WhyIsThisWordMatched», если оно не содержит цифр? И как можно исправить регулярное выражение, чтобы оно соответствовало только словам, содержащим и буквы, и цифры, и только буквы и цифры?
Public Sub TestMe()
Dim Rx As Object
Dim Txt As String
Set Rx = CreateObject("VBScript.RegExp")
Rx.Global = True
Rx.Pattern = "(^|\s)(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)($|\s)"
Txt = "WhyIsThisWordMatched XXX-111"
Txt = Rx.Replace(Txt, " ")
Debug.Print "Result: " & Txt
' Prints the string " XXX-111"
End Sub
Операции просмотра не используют символы, они просто подтверждают, возможно ли совпадение. Шаблон (?=.*[0-9])
гарантирует, что где-то впереди есть цифра, а (?=.*[a-zA-Z])
гарантирует, что где-то впереди есть буква, но не гарантирует, что обе буквы существуют в одном и том же слове.
Текущий шаблон (^|\s)(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)($|\s)
соответствует любому слову из букв и цифр, которое следует за пробелом или началом строки и предшествует пробелу или концу строки, при условии, что где-то в строке есть цифра и буква (не обязательно одним и тем же словом).
Этот шаблон, вероятно, должен решить непосредственную проблему:
(^|\s)(?=\w*[0-9])(?=\w*[a-zA-Z])[a-zA-Z0-9]+($|\s)
Итак, ваш код будет выглядеть примерно так:
Public Sub TestMe()
Dim Rx As Object
Dim Txt As String
Set Rx = CreateObject("VBScript.RegExp")
Rx.Global = True
Rx.Pattern = "(^|\s)(?=\w*[0-9])(?=\w*[a-zA-Z])[a-zA-Z0-9]+($|\s)"
Txt = "WhyIsThisWordMatched XXX-111 abc123"
Txt = Rx.Replace(Txt, " ")
Debug.Print "Result: " & Txt
' Prints the string "WhyIsThisWordMatched XXX-111 "
End Sub
Вы также можете использовать отрицательный просмотр вперед, что может быть лучше, поскольку оно гарантирует, что совпадению предшествует символ, не являющийся словом (например, пробел) или начало строки.
(?<!\S)(?=\S*[0-9])(?=\S*[a-zA-Z])\S+(?!\S)
Если вам не нужно использовать предварительный просмотр, то лучше всего использовать границу слова:
\b(?=\w*[0-9])(?=\w*[a-zA-Z])\w+\b
Вы можете использовать (?i)(?<=^|\s)(\b[a-z]+\b)(?=$|\s)|.
и заменить его на $1
:
Imports System.Text.RegularExpressions
Module R
Sub Main()
Dim Rx As New Regex("(?i)(?<=^|\s)(\b[a-z]+\b)(?=$|\s)|.")
Dim Txt As String = "WhyIsThisWordMatched XXX-111"
Txt = Rx.Replace(Txt, "$1")
Console.WriteLine("Result: " & Txt)
End Sub
End Module
Ваш пример показателен, но это
Visual Basic
, а неVBA
. Причина, по которой я используюCreateObject
вVBA
, заключается в том, чтобы убедиться, что он работает независимо от того, есть ли у пользователя ссылка на библиотеку, реализующую регулярные выражения, или нет. Спасибо за ваш пример.