VB pattern with unknown number of digits - regex

I am fairly new at VB and I need to write a function checking whether or not an ID is following the write pattern.
The pattern should be the letters ORG, accompanied by a - and then 1 to an infinite numbers of digits (ORG-1 or ORG-15793131354).
This is my code right now :
Sub CheckIdPattern
If MyFolder.Fields("USERTEXT221").value IsNot Nothing Then
Dim sId as String = MyFolder.Fields("USERTEXT221").value
Dim sMatch as Boolean = sId Like("ORG-#*")
If sMatch = False Then
Throw new exception("The ID entered is invalid, please use an ID starting with ORG- followed by numbers only")
End if
End if
End sub
As you can see I'm currently using "ORG-#*" which at least validate the beginning of the string, but permits to have any other characters at the end, causing bugs later in the program when we go and read these ID.
I also tried using System.Text.RegularExpressions (maybe not correctly though) but it failed because (I think) I can't import it in the program (I only have access to a small portion of the code and the rest is blocked by the software provider).
I know it seems like a pretty basic question so sorry for that and, thanks you very much for any help !

You can access the Regex.IsMatch method using a fully qualified name. Then, this code will do the trick for you:
Dim sId as String = "ORG-15793131354"
Dim sMatch as Boolean = System.Text.RegularExpressions.Regex.IsMatch(sId, "^ORG-\d+$")
If sMatch = False Then
Throw new exception("The ID entered is invalid, please use an ID starting with ORG- followed by numbers only")
End if
See IDEONE demo
The regex - "^ORG-\d+$" - matches ORG at the beginning of the string, then -, and then 1 or more digits up to the end of the string.

Perhaps you could check each character after your ORG- matching, using a for loop:
For i = 4 To sid.length
If Not(sid[i]>'0' And sid[i]<'9') Then
'throw your exception
End If
Next

Related

Regex to insert space with certain characters but avoid date and time

I made a regex which inserts a space where ever there is any of the characters
-:\*_/;, present for example JET*AIRWAYS\INDIA/858701/IDBI 05/05/05;05:05:05 a/c should beJET* AIRWAYS\ INDIA/ 858701/ IDBI 05/05/05; 05:05:05 a/c
The regex I used is (?!a\/c|w\/d|m\/s|s\/w|m\/o)(\D-|\D:|\D\*|\D_|\D\\|\D\/|\D\;)
I have added some words exceptions like a/c w/d etc. \D conditions given to avoid date/time values getting separated, but this created an issue, the numbers followed by the above mentioned characters never get split.
My requirement is
1. Insert a space after characters -:\*_/;,
2. but date and time should not get split which may have / :
3. need exception on words like a/c w/d
The following is the full code
Private Function formatColon(oldString As String) As String
Dim reg As New RegExp: reg.Global = True: reg.Pattern = "(?!a\/c|w\/d|m\/s|s\/w|m\/o)(\D-|\D:|\D\*|\D_|\D\\|\D\/|\D\;)" '"(\D:|\D/|\D-|^w/d)"
Dim newString As String: newString = reg.Replace(oldString, "$1 ")
formatColon = XtraspaceKill(newString)
End Function
I would use 3 replacements.
Replace all date and time special characters with a special macro that should never be found in your text, e.g. for 05/15/2018 4:06 PM, something based on your name:
05MANUMOHANSLASH15MANUMOHANSLASH2018 4MANUMOHANCOLON06 PM
You can encode exceptions too, like this:
aMANUMOHANSLASHc
Now run your original regex to replace all special characters.
Finally, unreplace the macros MANUMOHANSLASH and MANUMOHANCOLON.
Meanwhile, let me tell you why this is complicated in a single regex.
If trying to do this in a single regex, you have to ask, for each / or :, "Am I a part of a date or time?"
To answer that, you need to use lookahead and lookbehind assertions, the latter of which Microsoft has finally added support for.
But given a /, you don't know if you're between the first and second, or second and third parts of the date. Similar for time.
The number of cases you need to consider will render your regex unmaintainably complex.
So please just use a few separate replacements :-)

Regex Matching and Deleting/Replacing a string

So I am trying to parse through a file which has multiple "footers" (the file is an output that was designed for printing which my company wants to keep electronically stored...each footer is a new page and the new page is no longer needed as).
I am trying to look for and remove lines that look like:
1 of 2122 PRINTED 07/01/2013 04:46 Page : 1 of 11
2 of 2122 PRINTED 07/01/2013 04:46 Page: 2 of 11
3 of 2122 PRINTED 07/01/2013 04:46 Page: 3 of 11
and so on
I then want to replace the final line (which would read something like "2122 of 2122") with a "custom" footer.
I am using RegEx, but am very new to using it so how should my RegEx look in order to accomplish this? I plan on using the RegEx "count" function to find out when I've found the last line and then do a .replace on it.
I am using VB .NET, but can translate C# if required. How can I accomplish what I'm looking to do? Specifically I only care about matching/removing of a match so long as the # of matches > 1.
Here's one I created with RegExr:
/^(\d+\s+of\s+\d+)(?=\s+printed)/gim
It matches (number)(space)('of')(space)(number) at the beginning of a line, and only if it is followed by (space)('printed'), case insensitive. The /m flag turns ^ and $ into line-aware boundaries.
This is how I ended up doing it...
Private Function FixFooters(ByVal fileInput As String, Optional ByVal numberToLeaveAlone As Integer = 1) As String
Dim matchpattern As String = "^\d+\W+of\W+\d+\W+PRINTED.*$"
Dim myRegEx As New Regex(matchpattern, RegexOptions.IgnoreCase Or RegexOptions.Multiline)
Dim replacementstring As String = String.Empty
Dim matchCounter As Integer = myRegEx.Matches(fileInput).Count
If numberToLeaveAlone > matchCounter Then numberToLeaveAlone = matchCounter
Return myRegEx.Replace(fileInput, replacementstring, matchCounter - numberToLeaveAlone, 0)
End Function
I used myregextester.com to get the inital matchpattern. Since I wanted to leave the last footer alone (to manipulate it further later on) I created the numberToLeaveAlone variable to ensure we don't remove ALL of the variables. For the purposes of this program I made the default value 1, but that could be changed to zero (I only did it for readability in the calling code as I know I will ALWAYS want to leave one...but I do like to reuse code). It's fairly fast, I'm sure there are better ways out there, but this one made the most sense to me.

Keypress ISSUE VB.NET

I took many hours trying to solve this problem I have attempted, without success.
All I need is to validate a textbox:
Valid Chains:
10%
0%
1111111.12%
15.2%
10
2.3
Invalid Chains:
.%
12.%
.02%
%
123456789123.123
I need to validate the textbox with these valid chains, supporting the keypress event.
I tryed:
Private Sub prices_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles wholeprice_input_new_item.KeyPress, dozenprice_input_new_item.KeyPress, _
detailprice_input_new_item.KeyPress, costprice_input_new_item.KeyPress
Dim TxtB As TextBox = CType(sender, TextBox)
Dim fullText As String = TxtB.Text & e.KeyChar
Dim rex As Regex = New Regex("^[0-9]{1,9}([\.][0-9]{1,2})?[\%]?$ ")
If (Char.IsDigit(e.KeyChar) Or e.KeyChar.ToString() = "." Or e.KeyChar = CChar(ChrW(Keys.Back))) Then
If (fullText.Trim() <> "") Then
If (rex.IsMatch(fullText) = False And e.KeyChar <> CChar(ChrW(Keys.Back))) Then
e.Handled = True
MessageBox.Show("You are Not Allowed To Enter More then 2 Decimal!!")
End If
End If
Else
e.Handled = True
End If
End Sub
NOTE: The regex has to validate (Maximum 2 decimal places, and 9 integers) with an optional percent symbol.
Please help, I feel so frustrated trying to solve the problem without success
I think that you almost had the right answer. When I run your regex against the samples you supplied, they all fail. But if I remove the extra space at the end of the regex I get the expected successes and failures.
So currently your regex looks like this:
Dim rex As Regex = New Regex("^[0-9]{1,9}([\.][0-9]{1,2})?[\%]?$ ")
and it should look like
Dim rex As Regex = New Regex("^[0-9]{1,9}([\.][0-9]{1,2})?[\%]?$")
EDIT:
Ok I understand the issue more. The problem with the regex is that it will only allow a period if it is followed by one or two numbers. That works fine if you are evaluating the textbox value after someone has finished typing. But in your code, you are evaluating for each keypress, so you don't have a chance to type a number after the "."
I can see two possible solutions
Change the regex to allow 1. as a valid entry
Change when you evaluate the regex, perhaps trying to figure out a way to only evaluate the regex when the person has paused typing.
If you went with option 1, then we need to tweak the regex to something like this
"^[0-9]{1,9}((\.)|(\.[0-9]{1,2}(%)?)|(%))?$"
I changed the regex so that it will accept three optional endings to the text string (\.) will allow the string to end in a period , (\.[0-9]{1,2}(%)?) will allow the string to end period followed by one or two numbers and an optional percent sign, and (%) will allow the string to end in a percent sign. I broke the ending into the three options because I didn't want to allow something like 12.% to be valid. Also for this to work you will also need to add the percent sign to your first If statement
If (Char.IsDigit(e.KeyChar) Or e.KeyChar.ToString() = "." Or e.KeyChar.ToString() = "%" Or e.KeyChar = CChar(ChrW(Keys.Back))) Then
so that the regex runs when someone types the percent sign.

regular expressions and vba

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

Regex For Finding Ctypes with Int32

(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