Link to home
Start Free TrialLog in
Avatar of deshaw
deshawFlag for India

asked on

Replace whole word in string using Regex

Hi,

I want to replace whole words only (ignore cases) using regex.  I am using below method:

                   Set RegexObj = New RegExp

                    With RegexObj
                        .Pattern = "test"
                        .IgnoreCase = True
                        .Global = True
                    End With

                    objSafeMail.Body = RegexObj.Replace(objSafeMail.Body, "test2")

If string is "Mytest in regex test is the Testing for replace test" then above method gives below result.

       "Mytest2 in regex test2 is the Test2ing for replace test2"

but I want

      "Mytest in regex test2 is the Testing for replace test2"

Thanks.
Avatar of wellso
wellso
Flag of United Kingdom of Great Britain and Northern Ireland image

maybe ^(test)$ as your pattern?
Avatar of deshaw

ASKER

Nop the output will be same and it will not replace any of "test". It replace it only if complete string itself "test" and not  "Mytest in regex test is the Testing for replace test".
Thanks.
Avatar of Wayne Taylor (webtubbs)
Use this pattern....

    .Pattern = "\btest\b"

Wayne
Avatar of deshaw

ASKER

"\btest\b" - word boundery replaces all the "test" words. The output is    "Mytest2 in regex test2 is the Test2ing for replace test2". Also in  "this is test." it will not replace test as '.' is there.
Could you tell me is it possible to make regex something like this:
<Don't care what is here: space, dot,  nothing, or whatever but not alphanumeric> test <nothing should be here other than dot, space, newline or nothing>
Thanks,
>>The output is "Mytest2 in regex test2 is the Test2ing for replace test2"

No, it's not. The output is "Mytest in regex test2 is the Testing for replace test2". I know this because I tested it before posting.

>>Also in  "this is test." it will not replace test as '.' is there.

Yes, it will. The below example works exactly as you requested. Please try it. You will see the output is like this....

    "Testing - testing, XXXX, this is a XXXX."

Wayne
     Dim s As String
     s = "Testing - testing, test, this is a test."
 
    Dim RegexObj As New RegExp
 
     With RegexObj
          .Pattern = "\btest\b"
          .IgnoreCase = True
          .Global = True
     End With
 
     MsgBox RegexObj.Replace(s, "XXXX")

Open in new window

Avatar of deshaw

ASKER

Ok let me give you the real case: Please just run the attached code and you will come to know what I am asking. When you run the code, first message box will be displayed as
"Sys#123#1" string and next message box I am displaying original string and you could see that it will replace  "Sys#123#1#3"with the link string along with "Sys#123#1" though I have used word boundry given by you. Actually it is replacing  "Sys#123#1" in "Sys#123#1#3" string but it should not happen because we used "\b".
 Please let me know what is wrong.
Thanks,.

ub RegextTest()
 
    Const link = "http://mylink/Q/{match}/{NNN}"
    Const MY_PATTERN = "[a-zA-Z]{1,}#{1,1}[0-9]{1,}#{0,1}[0-9]{1,}"
    Dim oRE As Object
    Dim oMatches As Object
    Dim str As String
    Dim tmpstr As String
 
    Set oRE = CreateObject("VBScript.Regexp")
 
    With oRE
        .IgnoreCase = True
        .Global = True
        .MultiLine = True
        .Pattern = MY_PATTERN
    End With
    
    str = "Sys#123#1" & vbCrLf & "Admin#123#1#3" & vbCrLf & "Admin#123#1#3" & vbCrLf & "Sys#123#1#3"
    Set oMatches = oRE.Execute(str)
    
    For Each omatch In oMatches
         MsgBox omatch
         Dim s1() As String
         s1 = Split(omatch, "#")
         tmpstr = link
         tmpstr = Replace(tmpstr, "{match}", s1(0))
                   
         If UBound(s1) > 1 Then
              tmpstr = Replace(tmpstr, "{NNN}", s1(1) & "#" & s1(2))
         Else
              tmpstr = Replace(tmpstr, "{NNN}", s1(1))
         End If
                                        
         Set RegexObj = New RegExp
 
         With RegexObj
             .Pattern = "\b" & omatch & "\b"
             .IgnoreCase = True
             .Global = True
         End With
         
         str = RegexObj.Replace(str, tmpstr)
         MsgBox str
     Next
End Sub

Open in new window

Avatar of deshaw

ASKER

with    Const MY_PATTERN = "\b[a-zA-Z]{1,}#{1,1}[0-9]{1,}#{0,1}[0-9]{1,}\b" also gives same behavior.
Thanks.
Avatar of deshaw

ASKER

more simple. Why it is matching 4 times in given program? It should only 2 times. Isn't it?
Thanks.

Sub RegextTest()
 
    Const MY_PATTERN = "\b[a-zA-Z]{1,}#{1,1}[0-9]{1,}#{0,1}[0-9]{1,}\b"
    Dim oRE As Object
    Dim oMatches As Object
    Dim str As String
 
    Set oRE = CreateObject("VBScript.Regexp")
 
    With oRE
        .IgnoreCase = True
        .Global = True
        .Pattern = MY_PATTERN
    End With
    
    str = "Sys#123#1" & vbCrLf & "Admin#123#1#3" & vbCrLf & "Admin#123#2" & vbCrLf & "Sys#123#1#3"
    
    Set oMatches = oRE.Execute(str)
    
    MsgBox oMatches.Count
    
    For Each omatch In oMatches
         MsgBox omatch
     Next
End Sub

Open in new window

Avatar of deshaw

ASKER

In your example, if you put # after test, it will give below output
XXXX#ing - XXXX#ing, XXXX, this is a XXXX.
which is wrong.

 Dim s As String
     s = "Test#ing - test#ing, test, this is a test."
 
    Dim RegexObj As New RegExp
 
     With RegexObj
          .Pattern = "\btest\b"
          .IgnoreCase = True
          .Global = True
     End With
 
     MsgBox RegexObj.Replace(s, "XXXX")
 

Open in new window

I'll take a look at your example, but first, regarding "Test#ing", that's 2 words, "Test" and "ing", so is correctly replacing the words.
Using your last example, you could use this pattern

    [a-zA-Z]{1,}\#[0-9]{1,}\#[0-9]{1,}\r\n

If you could outline exactly what you are trying to achieve, we will probably be able to assist more.

Wayne
Avatar of deshaw

ASKER

If "Test#ing" two words then usage of word boundry "\b" won't work for me.
" [a-zA-Z]{1,}\#[0-9]{1,}\#[0-9]{1,}\r\n" either won't work in all situation. if valid string followed by space and not \r or \n then it won't return that as a match.
I tell you precisely what I want. I want to replace [a-zA-Z]#[0-9] or [a-zA-Z]#[0-9]#[0-9] strings and nothing else (e;g [a-zA-Z]#[0-9]#[0-9] #[0-9] should not be replaced) with the link  in whole string.
Let me know if I am not clear.
Thanks.
Avatar of deshaw

ASKER

I mean [a-zA-Z]#[0-9]#[0-9] pattern should not be detected and replaced in [a-zA-Z]#[0-9]#[0-9] #[0-9]  string.
Thanks.
If I understand correctly, try this pattern....

    [a-zA-Z]+(?:\#[0-9]+){1,2}(?!\#)\b

For this string....

Sys#123#1
Admin#123#1#3
Admin#123#2
Admin#123
Sys#123#1#3

...it will only match these...

Sys#123#1
Admin#123#2
Admin#123

Wayne
Avatar of deshaw

ASKER

Perfect, it identifies the correct matches only. Could you also tell me how we will replace it with the link. In attached script MY_PATTERN is what you have suggested. I want to replaced only matched items. It should not replaced unmatched item. for example currently Sys#123#1#3 is getting replaced by link.
If I keep same my pattern while replacing like below:
  Set RegexObj = New RegExp
 
         With RegexObj
             .Pattern = omatch & "(?:\#[0-9]+){1,2}(?!\#)\b"
             .IgnoreCase = True
             .Global = True
         End With
         
         str = RegexObj.Replace(str, tmpstr)
then it replacing all unmatched items. :-) I think something is missing. You can only help here. :-)
Complete code I have attached.
Thanks.

Sub RegextTest()
 
    Const MY_PATTERN = "[a-zA-Z]+(?:\#[0-9]+){1,2}(?!\#)\b"
    Const link = "http://mylink/Q/{match}/{NNN}"
 
    Dim oRE As Object
    Dim oMatches As Object
    Dim str As String
    Dim tmpstr As String
 
    Set oRE = CreateObject("VBScript.Regexp")
 
    With oRE
        .IgnoreCase = True
        .Global = True
        .MultiLine = True
        .Pattern = MY_PATTERN
    End With
    
    str = "Sys#123#1" & vbCrLf & "Admin#123#1#3" & vbCrLf & "Admin#123#1 Sys#123#1#3"
    Set oMatches = oRE.Execute(str)
    
    For Each omatch In oMatches
         MsgBox omatch
         Dim s1() As String
         s1 = Split(omatch, "#")
         tmpstr = link
         tmpstr = Replace(tmpstr, "{match}", s1(0))
                   
         If UBound(s1) > 1 Then
              tmpstr = Replace(tmpstr, "{NNN}", s1(1) & "#" & s1(2))
         Else
              tmpstr = Replace(tmpstr, "{NNN}", s1(1))
         End If
                                        
         Set RegexObj = New RegExp
 
         With RegexObj
             .Pattern = omatch & "(?:\#[0-9]+){1,2}(?!\#)\b"
             .IgnoreCase = True
             .Global = True
         End With
         
         str = RegexObj.Replace(str, tmpstr)
         MsgBox str
     Next
End Sub

Open in new window

Can you show exactly how these should look after the replacing is done?

Sys#123#1
Admin#123#1#3
Admin#123#2
Admin#123
Sys#123#1#3
Avatar of deshaw

ASKER

Out of below items:
Sys#123#1
Admin#123#1#3
Admin#123#2
Admin#123
Sys#123#1#3
following valid items should be get converted:
Sys#123#1
Admin#123#2
Admin#123

to
http://mylink/Q/Sys/123#1
http://mylink/Q/Admin/123#2
http://mylink/Q/Admin/123
 In my program below lines separating items by #.  The form "tmpstr" will be the final link that will replace original matched items.
         s1 = Split(omatch, "#")
         tmpstr = link
         tmpstr = Replace(tmpstr, "{match}", s1(0))
                   
         If UBound(s1) > 1 Then
              tmpstr = Replace(tmpstr, "{NNN}", s1(1) & "#" & s1(2))
         Else
              tmpstr = Replace(tmpstr, "{NNN}", s1(1))
         End If
 
Thanks.
OK, I think I have it. Try the below code and see how it goes.

Wayne
Sub RegextTest()
 
     Const MY_PATTERN = "([a-zA-Z]+)(\#[0-9]+){1,2}(?!\#)\b"
     Const link = "http://mylink/Q/"
 
     Dim oRE As Object
     Dim oMatches As Object, oMatch As Object
     Dim str As String
     Dim tmpstr As String
 
     Set oRE = CreateObject("VBScript.Regexp")
 
     With oRE
          .IgnoreCase = True
          .Global = True
          .MultiLine = True
          .Pattern = MY_PATTERN
     End With
 
     str = "Sys#123#1" & vbCrLf & "Admin#123#1#3" & vbCrLf & "Admin#123#1" & vbCrLf & "Sys#123#1#3"
 
     tmpstr = oRE.Replace(str, link & "$1/$&")
     Set oMatches = oRE.Execute(str)
     
     For Each oMatch In oMatches
          tmpstr = Replace(tmpstr, "/" & oMatch.submatches(0) & "#", "/")
     Next
 
     MsgBox str & vbCrLf & vbCrLf & tmpstr
 
End Sub

Open in new window

Avatar of deshaw

ASKER

fantabulous webtubbs, what a great logic !!! Could you please explain me what below line does?
  "([a-zA-Z]+)(\#[0-9]+){1,2}(?!\#)\b"

   tmpstr = oRE.Replace(str, link & "$1/$&")
   tmpstr = Replace(tmpstr, "/" & oMatch.submatches(0) & "#", "/")

 Could you please suggest any material to read about Regular Expression so that I can also think like you. :-)
Thanks.
ASKER CERTIFIED SOLUTION
Avatar of Wayne Taylor (webtubbs)
Wayne Taylor (webtubbs)
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of deshaw

ASKER

Then I think  "tmpstr = oRE.Replace(str, link & "$&")" will be enough. see attached code:
let me know if it is correct.
Thanks.

Sub RegextTest()
 
     Const MY_PATTERN = "([a-zA-Z]+)(\#[0-9]+){1,2}(?!\#)\b"
     Const link = "http://mylink/Q/"
 
     Dim oRE As Object
     Dim oMatches As Object, oMatch As Object
     Dim str As String
     Dim tmpstr As String
 
     Set oRE = CreateObject("VBScript.Regexp")
 
     With oRE
          .IgnoreCase = True
          .Global = True
          .MultiLine = True
          .Pattern = MY_PATTERN
     End With
 
     str = "Sys#123#1" & vbCrLf & "Admin#123#1#3" & vbCrLf & "Admin#123#1" & vbCrLf & "Sys#123#1#3"
 
     tmpstr = oRE.Replace(str, link & "$&")     
     MsgBox str & vbCrLf & vbCrLf & tmpstr
 
End Sub

Open in new window

If you do that, then this....

    Sys#123#1

...will end up like this....

    http://mylink/Q/Sys#123#1

I thought you wanted it to be "http://mylink/Q/Sys/123#1"?

Wayne
Avatar of deshaw

ASKER

Yup...you are correct. :-)
thanks.
Avatar of deshaw

ASKER

thanks.