Linq Substring by Index - vb.net

I got a List containing Integer values and a String. For example
DetermineDigits = {1,8,16,24}
String = "|Field1, Field2; Field26"
I want to get following output:
Dim output as List(Of String) = Feld1
Feld2
Feld3
I tried
For i = 1 To DetermineDigits.Count - 1
Dim NoOfDigits As Integer = DetermineDigits(i) - DetermineDigits(i - 1) - 1
tmpStr = String.Substring(DetermineDigits(i - 1), NoOfDigits)
list.add(tmpStr)
Next
which works, but I'd rather use Linq. Any ideas?

You may use Enumerable.Range() combined with Select() to iterate through DetermineDigits indexes:
Dim DetermineDigits = {1, 8, 16}
Dim Str = "|Field1, Field2; Field26"
Dim pos = DetermineDigits.Concat(New Integer() {Str.Length}).ToArray()
Dim output = Enumerable.Range(1, pos.Count() - 1) _
.Select(Function(i) Str.Substring(pos(i - 1), pos(i) - pos(i - 1)))
Mind the pos array which is the DetermineDigits with last substring end position added to it. Without this addition you're rather missing the last substring.
Alternatively you may consider using Zip() to get a list of {StartPos, EndPos} indexes for each of your substring.
That being said I suggest considering to use regex to extract your substrings. Those in your example can be easily grabbed with simple \w+ so you'll end up with quite compact code:
Dim Str = "|Field1, Field2; Field26"
Dim output = Regex.Matches(Str, "\w+").Cast(Of Match)().Select(Function(m) m.Value).ToList()
NB: don't forget to add Imports System.Text.RegularExpressions.
If your substring pattern is more complex, we may further elaborate the regex.

Related

VB.net, Linq -- How to compare items in List of Strings

I have got a list of Strings looking like this:
The items of the list of Strings are formated like this "#,#" where # stands for an integer number and # stands for a string or number.
I need to find the index of the first occurrence where the integer number is lower than the integer number of the previous item.
I am able to find it using a loop over all entries like this:
For X = 0 To UBound(TempList.ToArray) - 1
If Val(Left(TempList(X), InStr(TempList(X), ",") - 1)) > Val(Left(TempList(X + 1), InStr(TempList(X + 1), ",") - 1)) Then
Dim Result As String = TempList(X) & " -- " & TempList(X + 1)
End If
Next
I am sure that this can be done much smarter using linq - but my very poor knowledge regarding linq is not enough ...
Can someone please give me a hint?
Linq is cool but it is not necessarily faster. It is looping internally.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim TempList As New List(Of String) From {"450,245.5", "510,1", "520,1", "703,1", "704,0", "705,0", "706,0", "901,1.244", "921,3", "1,1", "2,1", "3,0"}
Dim Result As String = ""
For i As Integer = 1 To TempList.Count - 1
If CInt(TempList(i).Split(","c)(0)) < CInt(TempList(i - 1).Split(","c)(0)) Then
Result = $"{TempList(i)} At index {i} -- {TempList(i - 1)}"
Exit For 'Stop looping when found
End If
Next
MessageBox.Show(Result)
End Sub
You can use LINQ for the loop, but I do think a For / For Each is sufficient - see Mary's answer.
But at least, you could use LINQ to parse your list into something other than strings to make it more manageable when it's used. This will decouple your code a bit and will make it clearer. I'll hold the pair of data in a Tuple(Of Double, String). If I knew the first item was distinct, I would use a Dictionary(Of Double, String).
So for fun, you can use TakeWhile instead of a For / For Each.
Dim TempList = { "450,245.5", "510,1", "520,1", "701,0", "702,0", "703,1", "704,0", "705,0", "706,0", "720,0", "901.2,455", "921,3", "1,1", "2,1", "3,0"}
Dim parsedList = TempList.
Select(Function(s) s.Split(","c)).
Select(Function(ss) (CDbl(ss(0)), ss(1)))
Dim lastValue As Double = Double.NaN
Dim index = parsedList.TakeWhile(
Function(t)
Dim result = Double.IsNaN(lastValue) OrElse t.Item1 > lastValue
lastValue = t.Item1
Return result
End Function).Count()
Dim item = parsedList(index)
Console.WriteLine($"Index: {index}, number: {item.Item1}, string: {item.Item2}")
Index: 12, number: 1, string: 1
This is basically just making a For Each with LINQ. It's probably not necessary, and a simple loop is arguably more readable, and you won't gain any benefit in performance either.

VB .NET Convert string to array of bytes without converting the characters

I'm trying to split a string of 32 numerical characters into a 16 length Array of Byte and each value has to stay numerical
from "70033023311330000000004195081460" to array {&H_70, &H_03, &H_30, &H_23, ..}
I've tried multiple stuff but each time either it's the conversion that's wrong or I can't find the appropriate combination of functions to implement it.
'it splits but per 1 character only instead of two
str.Select(Function(n) Convert.ToByte(n, 10)).ToArray
'I also tried looping but then the leading zero disappears and the output is a string converted to HEX which is also not what I want.
Function ConvertStringToHexBinary(str As String) As Byte()
Dim arr(15) As Byte
Dim k = 0
For i As Integer = 0 To str.Length - 1
arr(k) = str(i) & str(i + 1)
k += 1
i += 1
Next
Return arr
End Function
Anyone got any suggestion what to do?
G3nt_M3caj's use of LINQ might be.. er.. appealing to the LINQ lovers but it's horrifically inefficient. LINQ is a hammer; not everything is a nail.
This one is about 3 times faster than the LINQ version:
Dim str As String = "70033023311330000000004195081460"
Dim byt(str.Length/2) as Byte
For i = 0 to str.Length - 1 Step 2
byt(i/2) = Convert.ToByte(str.Substring(i, 2))
Next i
And this one, which does it all with math and doesn't do any new stringing at all is just under 3 times faster than the above (making it around 9 times faster than the LINQ version):
Dim str As String = "70033023311330000000004195081460"
Dim byt(str.Length / 2) As Byte
For i = 0 To str.Length - 1
If i Mod 2 = 0 Then
byt(i / 2) = (Convert.ToByte(str(i)) - &H30) * &HA
Else
byt(i / 2) += Convert.ToByte(str(i)) - &H30
End If
Next i
Of the two, I prefer the stringy version because it's easier to read and work out what's going on - another advantage loops approaches often have over a LINQ approach
Do you need something like this?
Dim str As String = "70033023311330000000004195081460"
Dim mBytes() As Byte = str.
Select(Function(x, n) New With {x, n}).
GroupBy(Function(x) x.n \ 2, Function(x) x.x).
Select(Function(y) Convert.ToByte(New String(y.ToArray()), 10)).ToArray

How to increase numeric value present in a string

I'm using this query in vb.net
Raw_data = Alltext_line.Substring(Alltext_line.IndexOf("R|1"))
and I want to increase R|1 to R|2, R|3 and so on using for loop.
I tried it many ways but getting error
string to double is invalid
any help will be appreciated
You must first extract the number from the string. If the text part ("R") is always separated from the number part by a "|", you can easily separated the two with Split:
Dim Alltext_line = "R|1"
Dim parts = Alltext_line.Split("|"c)
parts is a string array. If this results in two parts, the string has the expected shape and we can try to convert the second part to a number, increase it and then re-create the string using the increased number
Dim n As Integer
If parts.Length = 2 AndAlso Integer.TryParse(parts(1), n) Then
Alltext_line = parts(0) & "|" & (n + 1)
End If
Note that the c in "|"c denotes a Char constant in VB.
An alternate solution that takes advantage of the String type defined as an Array of Chars.
I'm using string.Concat() to patch together the resulting IEnumerable(Of Char) and CInt() to convert the string to an Integer and sum 1 to its value.
Raw_data = "R|151"
Dim Result As String = Raw_data.Substring(0, 2) & (CInt(String.Concat(Raw_data.Skip(2))) + 1).ToString
This, of course, supposes that the source string is directly convertible to an Integer type.
If a value check is instead required, you can use Integer.TryParse() to perform the validation:
Dim ValuePart As String = Raw_data.Substring(2)
Dim Value As Integer = 0
If Integer.TryParse(ValuePart, Value) Then
Raw_data = Raw_data.Substring(0, 2) & (Value + 1).ToString
End If
If the left part can be variable (in size or content), the answer provided by Olivier Jacot-Descombes is covering this scenario already.
Sub IncrVal()
Dim s = "R|1"
For x% = 1 To 10
s = Regex.Replace(s, "[0-9]+", Function(m) Integer.Parse(m.Value) + 1)
Next
End Sub

String conversion for SQL select statement

Using a SELECT statement I query a database and get back a result in the format: name1,name2,name3
Depending on the database entry this result could have any number of names: name1,name2...name(n)
I would like to use this data to query another database like so:
SELECT Name, SerialNo, Model FROM InstrumentTable where ID=1 and InstName IN name1,name2,name3
In order to do this I need to convert name1,name2,name3 to ('name1','name2','name3')
I have tried splitting the String into an array of Strings
Dim ref1s As String = cmdf1.ExecuteScalar()
Dim fields() As String = Nothing
fields = ref1s.Split(",")
and then concatenating them in an array
For i As Integer = 0 To fields.Count - 1
MsgBox(String.Concat("'", fields(i), "'"))
Next
but I haven't been able to figure out how to do it yet.
Adding the brackets at the start and end of the string shouldn't be a problem just adding the quotes to each name and separating them with a comma is the issue.
Can anyone help me with this?
You got a bit previous
For i As Integer = 0 To fields.Count - 1
fields[i] = String.Concat("'",fields[i],"'")
Next
Then
strValue = fields.Join(',')
user557425,
Something like this might point you in the right direction:
Dim lst As List(Of String)
For i As Integer = 0 to fields.Count - 1
if i = fields.Count - 1 Then
lst.Add(fields(i) & "'")
Else
lst.Add(fields(i) & "','")
End if
Next
Dim sqlSB As StringBuilder
sqlSB.Append("SELECT * FROM TABLE WHERE BLAH IN(")
For each s As String in lst
sqlSB.Append(s)
Next
'use the stringbuilder as command text in a SqlCommand...

get string between other string vb.net

I have code below. How do I get strings inside brackets? Thank you.
Dim tmpStr() As String
Dim strSplit() As String
Dim strReal As String
Dim i As Integer
strWord = "hello (string1) there how (string2) are you?"
strSplit = Split(strWord, "(")
strReal = strSplit(LBound(strSplit))
For i = 1 To UBound(strSplit)
tmpStr = Split(strSplit(i), ")")
strReal = strReal & tmpStr(UBound(tmpStr))
Next
Dim src As String = "hello (string1) there how (string2) are you?"
Dim strs As New List(Of String)
Dim start As Integer = 0
Dim [end] As Integer = 0
While start < src.Length
start = src.IndexOf("("c, start)
If start <> -1 Then
[end] = src.IndexOf(")"c, start)
If [end] <> -1 Then
Dim subStr As String = src.Substring(start + 1, [end] - start - 1)
If Not subStr.StartsWith("(") Then strs.Add(src.Substring(start + 1, [end] - start - 1))
End If
Else
Exit While
End If
start += 1 ' Increment start to skip to next (
End While
This should do it.
Dim result = Regex.Matches(src, "\(([^()]*)\)").Cast(Of Match)().Select(Function(x) x.Groups(1))
Would also work.
This is what regular expressions are for. Learn them, love them:
' Imports System.Text.RegularExpressions
Dim matches = Regex.Matches(input, "\(([^)]*)\)").Cast(of Match)()
Dim result = matches.Select(Function (x) x.Groups(1))
Two lines of code instead of more than 10.
In the words of Stephan Lavavej: “Even intricate regular expressions are easier to understand and modify than equivalent code.”
Use String.IndexOf to get the position of the first opening bracket (x).
Use IndexOf again the get the position of the first closing bracket (y).
Use String.Substring to get the text based on the positions from x and y.
Remove beginning of string up to y+1.
Loop as required
That should get you going.
This may also work:
Dim myString As String = "Hello (FooBar) World"
Dim finalString As String = myString.Substring(myString.IndexOf("("), (myString.LastIndexOf(")") - myString.IndexOf("(")) + 1)
Also 2 lines.