I have to parse a string to obtain a specific value in it.
Here's an example of a string I need to parse: "#MSG 12,9: NINJUTSU"
Here I need to obtain the 12 value. The order of the value will not change, meaning that I will always aim the first number in the string; however the length of the string (12, 9, 58) is variable (but never negative) and the message (NINJUTSU) is also changing.
So far I proceed like this:
Dim tempErrorList As List(Of String) = errorMsg.Split(New Char() {":"}).ToList()
Dim listErr As List(Of String) = tempErrorList(0).Split(New Char() {","}).ToList()
Dim errCode As List(Of String) = listErr(0).Split(New Char() {" "}).ToList()
However I don't like it because of the 3 splits needed to obtain the values. I do not know how I could do it in one shot or fewer operations?
Similar to the deleted answer, you could use String.Split like so: errorMsg.Split(" ,:".ToCharArray()), which does what you're doing above but with one function call.
errorMsg.Split(" ,:".ToCharArray())(1) would give you the "12" you need.
Alternatively, you can use combinations of String.SubString() with String.IndexOf(), but the logic can become unwieldy and opaque. String.Split Alternatives (MSDN) gives more details on this approach.
Related
I'm not real experienced in using Linq, and am trying to understand .ToHashSet.
I'm using VB for this.
I have this code:
' Import the list of Windows Classes to exclude; one per line.
Dim strRead As String = My.Computer.FileSystem.ReadAllText("C:\Exclude.txt")
' Split the string into a string array
Dim strExcludes As String() = strRead.Split(ControlChars.CrLf.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
' Convert the String Array to a HashSet (Traditional Method)
Dim lList As New HashSet(Of String)(strExcludes)
This works as intended; I get each line from the text file into the HashSet as 1 line per Key.
Now, I want to see how to do the same using .ToHashSet. The following code seems to work fine with the exception of it returning as type <Of Char>, so I get each character in it's own Key, rather than each line in it's own Key.
' Convert the String Array to a HashSet (Using System.Linq Method) (Unfinished: Works, but needs to be converted from Char to String)
Dim lListLinq = strRead.ToHashSet()
I've Googled, and fought with it a bit, trying to get it to return as type <Of String>, but not much Google info out there for .ToHashSet for VB, or really much in C# either regarding this particular problem. I'm not seeing where to do the conversion; .ToHashSet itself also accepts no arguments.
Anyone know what I'm missing? I have a feeling it's something real simple slipping by me.
Invoking ToHashSet() on a string will yield a HashSet(Of Char) and will not give the expected result as you've witnessed.
Instead, what you need to do is split the string returned by ReadAllText and then call ToHashSet() on it to get a HashSet(Of String).
strRead.Split(ControlChars.CrLf.ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToHashSet()
I am using myArrayList.Contains(myString) and myArrayList.IndexOf(myString) to check if arrayList contains provided string and get its index respectively.
But, How could I check if contains a substring?
Dim myArrayList as New ArrayList()
myArrayList.add("sub1;sub2")
myArrayList.add("sub3;sub4")
so, something like, myArrayList.Contains("sub3") should return True
Well you could use the ArrayList to search for substrings with
Dim result = myArrayList.ToArray().Any(Function(x) x.ToString().Contains("sub3"))
Of course the advice to use a strongly typed List(Of String) is absolutely correct.
As far as your question goes, without discussing why do you need ArrayList, because array list is there only for backwards compatibility - to select indexes of items that contain specific string, the best performance you will get here
Dim indexes As New List(Of Integer)(100)
For i As Integer = 0 to myArrayList.Count - 1
If DirectCast(myArrayList(i), String).Contains("sub3") Then
indexes.Add(i)
End If
Next
Again, this is if you need to get your indexes. In your case, ArrayList.Contains - you testing whole object [string in your case]. While you need to get the string and test it's part using String.Contains
If you want to test in non case-sensitive manner, you can use String.IndexOf
Is it possible to have a string array as the value in a dictionary? I need to save the description (Hour2) as the key and as value being able to access both the price (elements_PR(4)) and the time offset (1). Is there a good way to do that?
Dim pr_val(2) As String
Dim PR As New Dictionary(Of String, pr_val)
PR.Add("Hour2", {elements_PR(4), "1"})
There is no reason why you can't do it - you could also use values of type Tuple(Of String, String), if the number of elements is fixed in advance - in this case, 2. It'd be easier to perform comparisons on, and would also be immutable, which is often a good idea.
You sure can. Try something like this:
Dim PR As New Dictionary(Of String, IEnumerable(Of String))
PR.Add("Hour2", {elements_PR(4), "1"})
It seems to me that you could create a class representing the price and the time offset. Therefore, you could do something like PR.Add("Hour2", instanceOfClass).
Depending on the meaning of the description in your situation, you could even include it in your class. It would allow you to use another approach with a List(Of YourClass) containing a list of items with the description, the price and the time offset. To retrieve an item by "key", you could then use some Linq.
Short answer - yes. Assuming the following was declared somewhere:
Dim elements_PR(4) As String : elements_PR(4) = "Hello"
Dim PR As New Dictionary(Of String, String())
You can either do:
PR.Add("Hour2", {elements_PR(4), "1"})
or
Dim pr_val() As String = {elements_PR(4), "1"}
PR.Add("Hour1", pr_val)
I'm just looking for some ideas with a little problem. I've a string that's a template for a message, for example:
Dear [[Guest.FirstName]],
We hope your are looking forward to your holiday in [[Booking.ResortName]]
My current system for replacing the spaceholder tokens (e.g. [[Guest.FirstName]]) is very inefficient, there's loops inside loops and it takes for too long.
What I'm looking for is a way that would go through the string until it finds [[something]], then replace that [[something]] with it's real value, then continue on through the string.
Please note to replace [[something]] then I need to have access to the space holder (i.e. i need to know if it's [[Guest.FirstName]] or [[Booking.ResortName]]).
Any suggestions for an efficient way to achieve this would be very much appreciated, I feel it should be fairly straightforward but everything I can think of ends up with loops inside loops again.
Thanks!
Phil.
There are many factors which will affect performance, so it's hard to say, without knowing all the specifics, what method will be most efficient. However, when it comes to coding simplicity, using a RegEx MatchEvaluator would be an excellent option. I'm sure you'll agree that it's much cleaner than whatever you are currently using:
Public Function ReplacePlaceholders(data As String) As String
Dim r As New Regex("\[\[(?<placeholder>.*?)\]\]")
data = r.Replace(data, New MatchEvaluator(AddressOf PlaceHolderReplacementEvaluator))
End Function
Private Function PlaceHolderReplacementEvaluator(match As Match) As String
Dim name As String = match.Groups("placeholder").Value
Return LookUpValueByPlaceholderName(name) ' Replace with value lookup logic here
End Function
If the total number of placeholders in the data is going to be rather small, and the list of possible placeholders is small, it's probably best to just have a list of them with their values and replace them like this:
Public Function ReplacePlaceholders(data As String) As String
Dim placeHolders As Dictionary(Of String, String) = LoadPlaceHolders()
For Each i As KeyValuePair(Of String, String) In placeHolders
data = data.Replace(i.Key, i.Value)
Next
Return data
End Function
Private Function LoadPlaceHolders() As Dictionary(Of String, String)
Dim placeholders As New Dictionary(Of String, String)
' Load data here
Return placeholders
End Function
If you really want the most efficient solution, though, going character by character and appending, as you go, to a StringBuilder or an output Stream, is going to be your best option. It's not going to be pretty, but if you post what you have to CodeReview, there may be some people who could find ways of making it slightly less ugly :)
The ValueList variable is defined as Dictionary(Of String, String)
The watch values captured show the data (tmpData) has a value of "1".
The ValueList is defined such that the replacement value for "1" is "Project Resource" as can be seen form the expansion of the SSGCol.ValueList Watch variable.
However, when I try to access the value I receive a KeyNotFoundException
I have done this sort of thing thousands of times in the past, but for some reason today I cannot get it to work. I must be missing something really obvious and need someone to take a fresh look and give me a slap when they see my obvious mistake.
Perhaps there are some unprintable characters in the string. Try comparing the bytes in the strings, for instance:
Dim bytes() As Byte = System.Text.Encoding.Unicode.GetBytes(tmpData)
This works for me...
Dim lst As New Dictionary(Of String, String)
lst.Add("1", "Test")
Dim tmpS As String = String.Empty
lst.TryGetValue("1", tmpS)