Given the following partial file example :
<SellGrey>True</SellGrey>
<SellWhite>false</SellWhite>
<SellGreen>false</SellGreen>
<SellBlue>false</SellBlue>
What is the best method to do a case-insensitive search and replace, while keeping the proper case on output.
For example:
<SellGrey>True</SellGrey>
or
<Sellgrey>tRue</Sellgrey>
would be what I am searching for, but the replacement, would always be :
<SellGrey>False</SellGrey>
Lastly, please do not get hung up on the "tags" as the file is malformed xml so reading/writing xml would bugger things up. Please look at the strings as just that -- a case-insensitive string search and replace, on a line by line basis.
Thanks in advance.
Since you didn't provide much detail about the tags, I used a dictionary for proper casing.
Dim input as String = "<Sellgrey>tRue</Sellgrey>"
Dim pattern as String = "<(?<tag>.+)>(?<value>(true|false))</.+>"
'building a dictionary to specify how to proper case
Dim tagFormatter as new Dictionary(Of String, String)
tagFormatter.Add("sellgrey", "ShellGrey")
tagFormatter.Add("sellwhite", "SellWhite")
tagFormatter.Add("sellgreen", "SellGreen")
tagFormatter.Add("sellblue", "SellBlue")
'build the new string using lambda
Dim result = Regex.Replace(input, pattern, _
Function(m) String.Format("<{0}>{1}</{0}>", _
tagFormatter(m.Groups("tag").Value.ToLower), _
If(m.Groups("value").Value = "true", "True", "False")), _
RegexOptions.IgnoreCase)
Related
I wish to select and add comments after certain words, e.g. “not”, “never”, “don’t” in sentences in a Word document with VBA. The Find/Replace with wildcards works fine, but “Use wildcards” cannot be selected with “Match case”. The RegEx can “IgnoreCase=True”, but the selection of the word is not reliable when there are more than one comments in a sentence. The Range.start seems to be getting modified in a way that I cannot understand.
A similar question was asked in June 2010. https://social.msdn.microsoft.com/Forums/office/en-US/f73ca32d-0af9-47cf-81fe-ce93b13ebc4d/regex-selecting-a-match-within-the-document?forum=worddev
Is there a new/different way of solving this problem?
Any suggestion will be appreciated.
The code using RegEx follows:
Function zRegExCommentor(zPhrase As String, tComment As String) As Long
Dim sTheseSentences As Sentences
Dim rThisSentenceToSearch As Word.Range, rThisSentenceResult As Word.Range
Dim myRegExp As RegExp
Dim myMatches As MatchCollection
Options.CommentsColor = wdByAuthor
Set myRegExp = New RegExp
With myRegExp
.IgnoreCase = True
.Global = False
.Pattern = zPhrase
End With
Set sTheseSentences = ActiveDocument.Sentences
For Each rThisSentenceToSearch In sTheseSentences
Set rThisSentenceResult = rThisSentenceToSearch.Duplicate
rThisSentenceResult.Select
Do
DoEvents
Set myMatches = myRegExp.Execute(rThisSentenceResult)
If myMatches.Count > 0 Then
rThisSentenceResult.Start = rThisSentenceResult.Start + myMatches(0).FirstIndex
rThisSentenceResult.End = rThisSentenceResult.Start + myMatches(0).Length
rThisSentenceResult.Select
Selection.Comments.Add Range:=Selection.Range
Selection.TypeText Text:=tComment & "{" & zPhrase & "}"
rThisSentenceResult.Start = rThisSentenceResult.Start + 1 'so as not to find the same phrase again and again
rThisSentenceResult.End = rThisSentenceToSearch.End
rThisSentenceResult.Select
End If 'If myMatches.Count > 0 Then
Loop While myMatches.Count > 0
Next 'For Each rThisSentenceToSearch In sTheseSentences
End Function
Relying on Range.Start or Range.End for position in a Word document is not reliable due to how Word stores non-printing information in the text flow. For some kinds of things you can work around it using Range.TextRetrievalMode, but the non-printing characters inserted by Comments aren't affected by these settings.
I must admit I don't understand why Word's built-in Find with wildcards won't work for you - no case matching shouldn't be a problem. For instance, based on the example: "Never has there been, never, NEVER, a total drought.":
FindText:="[n,N][e,E][v,V][e,E][r,R]"
Will find all instances of n-e-v-e-r regardless of the capitalization. The brackets let you define a range of values, in this case the combination of lower and upper case for each letter in the search term.
The workarounds described in my MSDN post you link to are pretty much all you can if you insist on RegEx:
Using the Office Open XML (or possibly Word 2003 XML) file format will let you use RegEx and standard XML processing tools to find the information, add comment "tags" into the Word XML, close it all up... And when the user sees the document it will all be there.
If you need to be doing this in the Word UI a slightly different approach should work (assuming you're targeting Word 2003 or later): Work through the document on a range-by-range basis (by paragraph, perhaps). Read the XML representation of the text into memory using the Range.WordOpenXML property, perform the RegEx search, add comments as WordOpenXML, then write the WordOpenXML back into the document using the InserXml method, replacing the original range (paragraph). Since you'd be working with the Paragraph object Range.Start won't be a factor.
I have a list like this
"Boring makes sense!"
"http://www.someurl.com/listsolo.php?username=fgt&id=46229&code="
"http://www.someurl2.com/members/listearn.php?username=mprogram&id=465301"
"All is there?"
"http://www.someurl.com/listsolo.php?username=loopa&id=46228&code="
"http://www.someurl3.com/members/mem.php?&mprogram"
"http://someurl4.com/members/mem.php?&loop"
I need to remove any kind of text on particular line including double quots with RegEx in vb.net
Dim fileName As String = "C:\Downloads\Links.txt"
Dim sr As New StreamReader(fileName)
While Not sr.EndOfStream
Dim re As String = sr.ReadLine()
If Not re.StartsWith("http") Then
re = Regex.Replace(re, "(^[A-Za-z]+)", "", RegexOptions.Multiline)
lblTest.Text += re.ToString()
End if
End While
sr.Close()
How to do it ...in simple way?
Using Linq, reading from file, filtering and re-writing back to it :
File.WriteAllLines("some path", From line In File.ReadAllLines("some path")
Where line.StartsWith("http"))
I figured it out :-), this regex
.[A-Za-z]\w+ .*
remove whole line of text with double quotas. I test regex here. Anyway, thanks for help.
I have this string for example: "Example_string.xml"
and i would like to add before the "." _DateTime of now so it will be like:
"Example_string_20151808185631.xml"
How can i achieve it? regex?
Yes, you can achieve that through the use of a look ahead. For instance:
Dim result As String = Regex.Replace("Example_string.xml", "(?=\.)", "_20151808185631")
Since the pattern only matches a position in the string (the position just before the period), rather than matching a portion of the text, the replace method doesn't actually replace any of the input text. It effectively just inserts the replacement text into that position in the string.
Alternatively, if you find that confusing, you could just match the period and then just include the period in the replacement text:
Dim result As String = Regex.Replace("Example_string.xml", "\.", "_20151808185631.")
If you don't want to just look for any period, and you want to be more safe about it (such as handling file names that contain multiple periods, then instead of \., you could use something like \.\w+$. However, if you need to make it that resilient, and it doesn't have to be done with RegEx, it would be better to use the Path.GetFileNameWithoutExtension and Path.GetExtension methods, as recommended by Crowcoder. For instance, you may also need to make it handle file names that have no extension, which even further complicates it.
or...
Path.GetFileNameWithoutExtension("Example_string.xml") + "_20151808185631" + Path.GetExtension("Example_string.xml")
How about:
Dim sFile As String = "Example_string.xml"
Dim sResult As String = sFile.ToLower.Replace(".xml", "_" & Format(Now(), "yyyyMMddHHmmss") & ".xml")
MsgBox(sresult, , sFile)
Does anyone know how to extract matches as strings from a RegExp.Execute() function?
Let me show you what I've gotten to so far:
Regex.Pattern = "^[^*]*[*]+"
Set myMatches = Regex.Execute(temp)
I want the object "myMatches" which is holding the matches, to be converted to a string. I know that there is only going to be one match per execution.
Does anyone know how to extract the matches from the object as Strings to be displayed lets say via a MsgBox?
Try this:
Dim sResult As String
'// Your expression code here...
sResult = myMatches.Item(0)
'// or
sResult = myMatches(0)
Msgbox("The matching text was: " & sResult)
The Execute method returns a match collection and you can use the item property to retrieve the text using an index.
As you stated you only ever have one match then the index is zero. If you have more than one match you can return the index of the match you require or loop over the entire collection.
This page has a lot of information on regex and seems to have what you want.
http://www.regular-expressions.info/vbscript.html
(Hey all,
I am looking for a little regex help...
I am trying to find all CType(expression,Int32) s and replace them with CInt(expression)
This, however, is proving quite difficult, considering there could be a nested Ctype(expression, Int32) within the regex match. Does anyone have any ideas for how to best go about doing this?
Here is what I have now:
Dim str As String = "CType((original.Width * CType((targetSize / CType(original.Height, Single)), Single)), Int32)"
Dim exp As New Regex("CType\((.+), Int32\)")
str = exp.Replace(str, "CInt($1)")
But this will match the entire string and replace it.
I was thinking of doing a recursive function to find the outer most match, and then work inwards, but that still presents a problem with things like
CType(replaceChars(I), Int32)), Chr(CType(replacementChars(I), Int32)
Any tips would be appreciated.
Input
returnString.Replace(Chr(CType(replaceChars(I), Int32)), Chr(CType(replacementChars(I), Int32)))
Output:
returnString.Replace(Chr(CInt(replaceChars(I))),Chr(CInt(replacementChars(I))))
Edit:
Been working on it a little more and have a recursive function that I'm still working out the kinks in. Recursion + regex. it kinda hurts.
Private Function FindReplaceCInts(ByVal strAs As String) As String
System.Console.WriteLine(String.Format("Testing : {0}", strAs))
Dim exp As New Regex("CType\((.+), Int32\)")
If exp.Match(strAs).Success Then
For Each match As Match In exp.Matches(strAs)
If exp.Match(match.Value.Substring(2)).Success Then
Dim replaceT As String = match.Value.Substring(2)
Dim Witht As String = FindReplaceCInts(match.Value.Substring(2))
System.Console.WriteLine(strAs.IndexOf(replaceT))
strAs.Replace(replaceT, Witht)
End If
Next
strAs = exp.Replace(strAs, "CInt($1)")
End If
Return strAs
End Function
Cheers,
What do you guys think of this?
I think it does it quite nicely for a variety of cases that I have tested so far...
Private Function FindReplaceCInts(ByVal strAs As String) As String
Dim exp As New Regex("CType\((.+), Int32\)")
If exp.Match(strAs).Success Then
For Each match As Match In exp.Matches(strAs)
If exp.Match(match.Value.Substring(2)).Success Then
Dim replaceT As String = match.Value.Substring(2)
Dim Witht As String = FindReplaceCInts(match.Value.Substring(2))
strAs = strAs.Replace(replaceT, Witht)
End If
Next
strAs = exp.Replace(strAs, "CInt($1)")
End If
Return strAs
End Function
try to use this (?!CType\(.+, )Int32 regex instead of yours
You need to use negative look ahead to accomplish your task.
Check regex at this site
I've tried this in VS 2008 (no copy of VS 2010 to try it out), using the Find & Replace dialog:
Regular Expression: CType\({.+}, Int32\)
Replace With: CInt(\1)
It won't fix the nested situations in one pass, but you should be able to continue searching with that pattern and replacing until no other matches are found.
BTW: That dialog also provides a link to this help page explaining characters used the VS flavor of regex http://msdn.microsoft.com/en-us/library/aa293063(VS.71).aspx