My coworker needs me to write him a regular expression for his vb.net app.
I do not know vb and he does not know regex.
The regex he needs is:
/.*web id: ?(\d+).*/i
Basically he needs to search a string for something like "web id: 345" or "web id:2534" and retrieve the ID.
He took what I gave him above and was able to put this together:
Dim strPattern As String = ".*web id: ?(\d+).*"
Dim strReplacement$ = "$1"
GetWebId$ = Regex.Replace(LCase$(strNote$), strPattern$, strReplacement$)
However I am not sure how you pass the case-insensitive flag? (his current fix for that is making the whole string lowercase first)
Also one thing I can't seem to figure out is when he runs this on a string with multiple lines, any text that is not on the same line as "web id: \d" is also being returned which i find strange.
Use the RegexOptions.IgnoreCase flag:
Regex.Replace(strNote, strPattern, strReplacement, RegexOptions.IgnoreCase)
If you are going to ignore case there should be no need to use LCase. I also find it odd that you have all those $ symbols in your variable names - they shouldn't be valid in either C# or VB.NET.
EDIT #2: I realize you may have wanted to replace the entire line that matched with the $1 replacement pattern to match the ID. If you have a need to use multiple options you can Or them together as follows:
Regex.Replace(input, pattern, replacement, RegexOptions.IgnoreCase Or RegexOptions.Singleline)
EDIT #1: you are using the wrong method to extract the ID. You have a group (\d+) to capture the ID, but you are using Regex.Replace on your match, which is why you get everything else in the text. To match the ID use the following:
Dim input As String = "foo web id:2010 bar"
Dim pattern As String = ".*web id: ?(\d+).*"
Dim m As Match = Regex.Match(input, pattern, RegexOptions.IgnoreCase)
If m.Success Then
Dim id As String = m.Groups(1).Value
Console.WriteLine("ID: " & id)
Else
Console.WriteLine("No Match!")
End If
You will notice we refer to Groups(1) which holds the value captured by the (\d+) group. Patterns with more groups may lead to confusion, especially with nested groups. In those cases you can use named groups. Here is the same code updated to use named groups:
Dim input As String = "foo web id:2010 bar"
Dim pattern As String = ".*web id: ?(?<ID>\d+).*" ' group name added '
Dim m As Match = Regex.Match(input, pattern, RegexOptions.IgnoreCase)
If m.Success Then
' refer to group by group name '
Dim id As String = m.Groups("ID").Value
Console.WriteLine("ID: " & id)
Else
Console.WriteLine("No Match!")
End If
Kind of unrelated, but this code is a collection of things you shouldn’t do in VB.NET.
You shouldn’t use the old $ suffix on string variables, and likewise you shouldn’t use old functions such as LCase$. There are equivalent functions in the framework that should be used. You can also tell your friend to always enable Option Strict while where at it. This will catch a lot of potential bugs.
Furthermore, to set the return value of a function, the … “more established” method is to use Return …, not Functionname = ….
So the “correct” code will look like this:
''// I’m assuming that `GetWebId` is the name of the function we’re in.
Function GetWebId(note As String) As String
Dim pattern As String = ".*web id: ?(\d+).*"
Dim replacement As String = "$1"
Return Regex.Replace(note.ToLower(), pattern, replacement)
End Function
See Ahmad’s solution of how to get the “ignorecase” flag into the expression.
Related
Note: I'm not posting all code due to it's over 500 lines, I'll show a summary of what I'm trying to accomplish and the issue:
I have a string array that looks like this:
New_BMWM3889;New_LEXIS600;789858;Used_VOL9998
I need to call a routine (the same routine) that will add formatting to the value. I've tried a for each loop, but it's only grabbing the last value of the string array.
I've tried something like this:
dim cars as String = "New_BMWM3889;New_LEXIS600;789858;Used_VOL9998"
dim tmp as String() = cars.Split(";")
dim vin as String
For Each c in tmp
If p.Conatains("New") Then
vin = FormatVin("New", "#", newFormat('0000'))
Else
vin = FormatVin("No Model", "&", newFormat('####'),
End If
Next
so, I have to call the same routine and pass different parameters to the FormatVin routine, however, when I run this I'm only getting the last value of the string array. The formatVin does format validation and will change the format if needed, but that's not the issue, how can I call that same routine but pass different parameters based on if the string in the string array has a prefix or not? Then once the formatting is completed, all of the new formatted values will be passed into a String builder to be used to pass to SQL,
so,
Need to grab all values from the string array
call the routine with the correct parameters based off of the string value.
take all the new formatted strings and passed as one string into a new routine that builds a SQL statement. I know it's a mess, and I'm not sure if it can really be done cleanly if at all. So at the end I should have so I can pass this into my where clause
New_BMWM3889000;New_LEXIS600000;000000789858;Used_VOL9998000
It's hard to say exactly but I think that you should be using something along these lines:
Dim cars = "New_BMWM3889;New_LEXIS600;789858;Used_VOL9998"
Dim tmp = cars.Split(";"c)
For i = 0 To tmp.GetUpperBound(0)
Dim vin = tmp(i)
If vin.Conatains("New") Then
vin = FormatVin("New", vin, newFormat('0000'))
Else
vin = FormatVin("No Model", vin, newFormat('####'),
End If
tmp(i) = vin
Next
cars = String.Join(";", tmp)
It seems like you need to get data out of and into that array. You haven't told us what FormatVin does but I would also assume that you have to pass in the data from the array and get back out a modified version to put back into the array. I might be off on some of the detail, given your vague explanation, but I think this is the basic structure you need.
How do I get content of list to be displayed or stored in one line.
I get the content but in one line each, I need it to be in one line all.
Dim ride as string
For Each ride In myListFlight
Console.WriteLine(ride)
Next
Are you looking for this?
Dim ride as string
ride = String.Join(",", ListOfStrings)
I think what you're looking for is the Aggregate linq function.
What aggregate does is combine entries using a Func. With strings, this can be as simple as:
Dim combined as string
combined = myList.Aggregate(Function(byval a, byval b) a & " " & b)
With custom classes, it becomes a bit trickier - you usually have to translate to some sort of 'addable' class (such as a string), like:
Dim intermediary as IEnumerable(Of string)
intermediary = myList.Select(Function(x) x.ToString())
Dim combined as string
combined = intermediary.Aggregate(... etc ...)
(Pardon if the syntax isn't 100% correct. I'm a C# dev, so my VB-Linq knowledge is a bit rusty.)
I'm learning to read text files and Streamreader is the only class I know until now for that purpose.
Until now I've seen this class lets me read the entire file(.ReadToEnd), line by line(.ReadLine) or character by character(.Read).
However I can't figure how to read substrings delimited by , and solve this:
( Following 4 lines are the content of textfile.txt)
COLUMN1,MAIL1,COLUMN3,COLUMN4,COLUMN5,MAIL2
".","user#DOMAIN.EDU.PE","1","2013-05-08 00:00:00","0","user#DOMAIN.EDU.PE"
".","id#DOMAIN1.COM.PE","1","2013-05-08 00:00:00","0","HADSA7#DOMAIN1.COM.PE"
".","myid#DOMAIN2.COM.PE","1","2013-05-08 00:00:00","0","4671#DOMAIN2.COM.PE"
If the first email address is equal to the second, do:
Numberofmatched=Numberofmatched+1
If not
Numberofunmatched=Numberofunmatched+1
Take in consideration domain name can change and email addresses have variable lenght.
Any help?
Here's another method to read a text-file. You can use the System.IO.File class, for example File.ReadLines/File.ReadAllLines or File.ReadAllText.
Use String.Split to get a String(), one string for each column. Since the delimiter seems to be ,instead of " use String.Split(","c).
You can use following LINQ query which can increase readability:
Dim allLines = File.ReadAllLines("Path")
Dim data = From line In allLines.Skip(1) ' skip the header-line
Where Not String.IsNullOrWhiteSpace(line)
Let fields = line.Split(","c)
Where fields.Length = 6
Select fields
Dim Numberofmatched As Int32 = data.Count(Function(fields) fields(1) = fields(5))
Dim Numberofunmatched As Int32 = data.Count(Function(fields) fields(1) <> fields(5))
Note that you should use an available CSV-parser instead of reinventing the wheel since they support quoting characters and a lot of other things. One recommendable in the Visual-Basic namespace is the TextFieldParser class.
Hey guys I'm stuck with this question. Please help.
I want to write a program that can extract alphabetical characters and special characters from an input string. An alphabetical character is any character from "a" to "z"(capital letters and numbers not included") a special character is any other character that is not alphanumerical.
Example:
string = hello//this-is-my-string#capetown
alphanumerical characters = hellothisismystringcapetown
special characters = //---#
Now my question is this:
How do I loop through all the characters?
(the for loop I'm using reads like this for x = 0 to strname.length)...is this correct?
How do I extract characters to a string?
How do I determine special characters?
any input is greatly appreciated.
Thank you very much for your time.
You could loop through each character as follows:
For Each _char As Char In strname
'Code here
Next
or
For x as integer = 0 to strname.length - 1
'Code here
Next
or you can use Regex to replace the values you do not need in your string (I think this may be faster but I am no expert) Take a look at: http://msdn.microsoft.com/en-us/library/xwewhkd1.aspx
Edit
The replacement code will look something as follows although I am not so sure what the regular expression (variable called pattern currently only replacing digits) would be:
Dim pattern As String = "(\d+)?" 'You need to update the regular expression here
Dim input As String = "123//hello//this-is-my-string#capetown"
Dim rgx As New Regex(pattern)
Dim result As String = rgx.Replace(input, "")
Since you need to keep the values, you'll want to loop through your string. Keeping a list of characters as a result will come in handy since you can build a fresh string later. Then take advantage of a simple Regex test to determine where to place things. The psuedo code looks something like this.
Dim alphaChars As New List(Of String)
Dim specialChars As New List(Of String)
For Each _char As Char in testString
If Regex.IsMatch(_char, "[a-z]")) Then
alphaChars.Add(_char)
Else
specialChars.Add(_char)
End If
Next
Then If you need to dump your results into a full string, you can simply use
String.Join(String.Empty, alphaChars.ToArray())
Note that this code makes the assumption that ANYTHING else than a-z is considered a special character, so if needs be you can do a second regular expression in your else clause to test for you special characters in a similar manner. It really depends on how much control you have over the input.
In one of the ms-access table I work with we have a text field with a set size.
At the end of this field there is some extra code that varies depending on the situation.
I'm looking for a way to remove one of these code but even when the last part is truncated by the field maximum size.
Let's call the field "field" and the code I'm looking to remove "abc-longcode".
If I use the replace SQL function with the string abc-longcode the query will only work when the code is complete.
If I also want my update query (that does nothing but remove this specific code at the end of my field) to work on incomplete codes how would that translate into ms-SQL?
It would have to remove (or replace with "" to be precise) all of the following (example of course, not the real codes):
abc-longcode
abc-longcod
abc-longco
abc-longc
abc-long
abc-lon
abc-lo
abc-l
Obviously I could do that with several queries. Each one replacing one of the expected truncated codes... but it doesn't sound optimal.
Also, when the field is big enough to get all of the code, there can sometime be extra details at the end that I'll also want to keep so I cannot either just look for "abc-l" and delete everything that follows :\
This query (or queries if I can't find a better way) will be held directly into the .mdb database.
So while I can think of several ways to do this outside of a ms-sql query, it doesn't help me.
Any help?
Thanks.
You can write a custom VBA replace method that will replace any of the given cases {"abc-longcode", ... "abc-l"}. This is essentially the same tack as your "several queries" idea, except it would only be one query. My VBA is rusty, but something like:
public function ReplaceCodes(str as string) as string
dim returnString as string
returnString = str
returnString = replace(returnString,"abc-longcode","")
// ... etc...
ReplaceCodes = returnString
end function
I may have gotten the parameter order wrong on replace :)
I would use my own custom function to do this using the split function to get the first part of the string. You can then use that value in the update query.
Public Function FirstPart(thetext As String) As String
Dim ret As String
Dim arrSplitText As Variant
arrSplitText = Split(thetext, "-")
ret = arrSplitText(0)
FirstPart = ret
End Function
Can you use:
Left(FieldX,InStr(FieldX,"abc-")-1)
EDIT re Comment
If there is a space or other standard delimiter:
IIf(InStr(InStr(FieldX, "abc-"), FieldX, " ") = 0, Left(FieldX, InStr(FieldX, "abc-") - 1), Replace(FieldX, Mid(FieldX, InStr(FieldX, "abc-"), InStr(InStr(FieldX, "abc-"), FieldX, " ") - InStr(FieldX, "abc-")), ""))