VB determining values within a string - vb.net

I am looking for assistance with my program. I have a user enter 6 digits; of these the input must be alpha-numeric. I have already done the TryParse method for the numbers, but I am looking for validation that the string contains an alpha.
I am aware you must use ASC but am unsure both on how to develop a range say Asc((Chr(65) <= Chr(90))) (between A-Z) and also to say (IF my input contains any of these values within the 6 characters, to return true. I keep getting an overload resolution and wish to know how to properly code so the variables are accurate.

This is a great place to use a regular expression
Dim input = ...
If Regex.IsMatch(input, "^\w+$") AndAlso input.Length = 6 Then
' It's a match
Else
' It's not a match
End If
This will match any string which consists only of letters that has length equal to 6

You can iterate through each char and check if it's a letter. If so, set a flag to true.
Dim containsAlpha Boolean = False
For i As Integer = 0 To input.Length - 1
If Char.IsLetter(input(i)) Then
containsAlpha = True
Exit For
End If
Next
Char.IsLetter will match Unicode alphabetic letters, so not just Latin A-Z (which may or may not be what you actually want).

Related

Extract first two digits that comes after some string in Excel

I have a row with values something like this, How to extract first two digits that come after the text 'ABCD' to another cell, any formula or vba? There may be a few chars in between or sometimes none.
ABCD 10 sadkf sdfas
ABCD-20sdf asdf
ABCD 40
ABCD50 asdf
You can do this with a worksheet formula. No need for VBA.
Assuming you do not need to test for the presence of two digits:
=MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&"1234567890")),2)
If you need to test for the presence of two digits, you can try:
=IF(ISNUMBER(-RIGHT(MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&"1234567890")),2),1)),MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&"1234567890")),2),"Invalid")
In general, it is always a good idea to show some code in StackOverflow. Thus, you show that you have tried something and you give some directions for the answer.
Concerning the first two digits extract, there are many ways to do this. Starting from RegEx and finishing with a simple looping of the chars and checking each one of them.
This is the loop option:
Public Function ExtractTwoDigits(inputString As String) As Long
Application.Volatile
Dim cnt As Long
Dim curChar As String
For cnt = 1 To Len(inputString)
curChar = Mid(inputString, cnt, 1)
If IsNumeric(curChar) Then
If Len(ExtractTwoDigits) Then
ExtractTwoDigits = ExtractTwoDigits & curChar
Exit Function
Else
ExtractTwoDigits = curChar
End If
End If
Next cnt
ExtractTwoDigits = -1
End Function
Application.Volatile makes sure that the formula recalculates every time;
-1 is the answer if no two digits exist in the inputString;
IsNumeric checks whether the string inside is numeric;
As a further step, you may try to make the function a bit robust, extracting the first 1, 3, 4 or 5 digits, depending on a parameter that you put. Something like this =ExtractTwoDigits("tarato123ra2",4), returning 1232.
RegEx Version:
Public Function GetFirstTwoNumbers(ByVal strInput As String) As Integer
Dim reg As New RegExp, matches As MatchCollection
With reg
.Global = True
.Pattern = "(\d{2})"
End With
Set matches = reg.Execute(strInput)
If matches.Count > 0 Then
GetFirstTwoNumbers = matches(0)
Else
GetFirstTwoNumbers = -1
End If
End Function
You have to enable Microsoft Regular Expressions 5.5 under extras->references. The pattern (\d{2}) matches 2 digits, return value is the number, if not existing -1.
Note: it only extracts 2 successive numbers.
If you place this function into a module, you can use it like normal formula.
Here a great site to to get into regEx.

how to get each hexadecimal value present in the text box into an array?

In my application, the users may need to add hexadecimals in the textbox during run time and I would like to get each hexadecimal value in an array by removing the spaces if there are any.
For example, the data in the textbox is "ff 00 ff 1a ff 00". I could able to get each hexadecimal as an array with the help of split. But, now I am trying to remove all the spaces as some users may enter the hexadecimals without giving the space. For example, the user my enter as "ff 00 ff1a ff 00". So, in this case the third array contains "ff1a", which is not true. I know how to remove the spaces, but cannot able to figure out the way to get each hexadecimal into an array.
'Used to split the strings based on the spaces, which is not useful
'Dim extraData As String() = Split(TextBox8.Text, " ")
'Used to remove the spaces
Dim myString = TextBox8.Text.Replace(" ", "")
Any suggestion will be appreciated.
You can use something like:
Dim input As String = TextBox1.Text
Dim list As New List(Of String)
input = input.Replace(" ", "")
For i As Integer = 0 To input.Length - 1 Step 2
list.Add(input.Substring(i, 2))
Next
Dim array = list.ToArray()
Note - The length of the input (after removing spaces) must be even. Otherwise, it may throw an exception.
If I convert the method from C# to VB.NET given in this answer:
Public Function StringToByteArray(hex As [String]) As Byte()
Dim NumberChars As Integer = hex.Length
Dim bytes As Byte() = New Byte(NumberChars / 2 - 1) {}
For i As Integer = 0 To NumberChars - 1 Step 2
bytes(i / 2) = Convert.ToByte(hex.Substring(i, 2), 16)
Next
Return bytes
End Function
Then you can call it like this:
StringToByteArray(YourInputString.Replace(" ", ""))
This will return an array of bytes and will also validate the input because it will thrown an exception if invalid characters are used in the input (like non-hex characters).
I know you already have accepted an answer, however, I'd like to suggest another alternative. I'm assuming, based on the context of your question and the example that you provided, that your intention is to parse a list of bytes, where each byte is represented by a two digit hexadecimal value.
If you use regex to find your matches, it will be more powerful. For instance, you can easily ignore all white-space characters (e.g. tabs, new-lines) and you can easily validate the data to make sure that only properly formatted bytes are in the string (i.e. 00 - FF). For instance, you could do something like this:
Dim bytes As New List(Of String)()
Dim m As Match = Regex.Match(TextBox1.Text, "^\s*((?<byte>[a-fA-F0-9]{2})\s*)*$")
If m.Success Then
Dim g As Group = m.Groups("byte")
If g.Success Then
For Each c As Capture In g.Captures
bytes.Add(c.Value)
Next
End If
Else
MessageBox.Show("Input is not properly formatted")
End If
However, if the idea is to parse the actual byte values, you can do so using Byte.Parse, like this:
Dim bytes As New List(Of Byte)()
Dim m As Match = Regex.Match(TextBox1.Text, "^\s*((?<byte>[a-fA-F0-9]{2})\s*)*$")
If m.Success Then
Dim g As Group = m.Groups("byte")
If g.Success Then
For Each c As Capture In g.Captures
bytes.Add(Byte.Parse(c.Value, NumberStyles.HexNumber))
Next
End If
Else
MessageBox.Show("Input is not properly formatted")
End If
Both of those examples use the same regex pattern to find all of the hexadecimal bytes in the string. The pattern it uses is:
^\s*((?<byte>[a-fA-F0-9]{2})\s*)*$
Here's the meaning of the regex pattern:
$ - The match must start at the beginning of the string (i.e. no invalid text can come before the bytes)
\s* - Any number of white-space characters can come before the first byte
\s - Any white-space character
* - Zero or more times
((?<byte>[a-fA-F0-9]{2})\s*)* - Any number of bytes, each separated by any number of white-space characters
( - Begins the group so that we can later apply a kleene star to the whole group (which means the whole group can repeat any number of times)
(?<byte> - Begins another, inner group which is named "byte". It is given a name so that we can easily reference the values captured by the group in the VB code.
[a-fA-F0-9]{2} - A two-digit hexadecimal byte (i.e. 00 - FF)
[a-fA-F0-9] - Any character between a and f or between A and F or between 0 and 9
{2} - There must be exactly two characters matching that specification
) - Ends the group named "byte". Notice that this named-group only captures the two actual hexadecimal digits. It does not capture any of the white-space between the bytes.
\s* - There can be any number of white-space characters after a byte
) - The ends outer group which includes a byte and all of the white-space that comes after it
* - The aforementioned kleene star meaning that the outer-group can repeat any number of times
$ - The match must end at the ending of the string (i.e. no invalid text can come after the bytes)

Extract 5-digit number from one column to another

I need help with extracting 5-digit numbers only from one column to another in Excel 2010. These numbers can be in any position of the string (beginning of the string, anywhere in the middle, or at the end). They can be within brackets or quotes like:
(15478) or "15478" or '15478' or [15478]
I need to ignore any numbers that are less than 5 digits and include numbers that start with 1 or more leading zeros (like 00052, 00278, etc.) and ensure that leading zeros are copied over to the next column. Could someone help me with either creating a formula or UDF?
Here is a formula-based alternative that will extract the first 5 digit number found in cell A1. I tend to prefer reasonably simple formula solutions over VBA in most situations as formulas are more portable. This formula is an array formula and thus must be entered with Ctrl+Shift+Enter. The idea is to split the string up into every possible 5 character chunk and test each one and return the first match.
=MID(A1,MIN(IF(NOT(ISERROR(("1"&MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE)),5)&".1")*1))*ISERROR(MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))+5,1)*1)*ISERROR(MID(A1,ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))-1,1)*1),ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE)),9999999999)),5)
Let's break this down. First we have an expression I used twice to return an array of numbers from 1 up to 4 less than the length of your initial text. So if you have a string of length 10 the following will return {1,2,3,4,5,6}. Hereafter the below formula will be referred to as rowlist. I used R1C1 notation to avoid potential circular references.
ROW(INDIRECT("R1C[1]:R"&(LEN(A1)-4)&"C[1]",FALSE))
Next we will use that array to split the text into an array of 5 letter chunks and test each chunk. The test being performed is to prepend a "1" and append ".1" then verify the chunk is numeric. The prepend and append eliminate the possibility of white space or decimals. We can then check the character before and the character after to make sure they are not numbers. Hereafter the below formula will be referred to as isnumarray.
NOT(ISERROR(("1"&MID(A1,rowlist,5)&".1")*1))
*ISERROR(MID(A1,rowlist+5,1)*1)
*ISERROR(MID(A1,rowlist-1,1)*1)
Next we need to find the first valid 5 digit number in the string by returning the current index from a duplicate of the rowlist formula and returning a large number for non-matches. Then we can use the MIN function to grab that first match. Hereafter the below will be referred to as minindex.
MIN(IF(isnumarray,rowlist,9999999999))
Finally we need to grab the numeric string that started at the index returned by the MIN function.
MID(A1,minindex,5)
The following UDF will return the first five digit number in the string, including any leading zero's. If you need to detect if there is more than one five digit number, the modifications are trivial. It will return a #VALUE! error if there are no five-digit numbers.
Option Explicit
Function FiveDigit(S As String, Optional index As Long = 0) As String
Dim RE As Object
Set RE = CreateObject("vbscript.regexp")
With RE
.Pattern = "(?:\b|\D)(\d{5})(?:\b|\D)"
.Global = True
FiveDigit = .Execute(S)(index).submatches(0)
End With
End Function
As you may see from the discussion between Mark and myself, some of your specifications are unclear. But if you would want to exclude decimal numbers, when the decimal portion has five digits, then the regex pattern in my code above should be changed:
.Pattern = "(?:\d+\.\d+)|(?:\b|\D)(\d{5})(?:\b|\D)"
I just wrote this UDF for you , basic but will do it...
It will find the first 5 consecutive numbers in a string, very crude error checking so it just says Error if anything isn't right
Public Function GET5DIGITS(value As String) As String
Dim sResult As String
Dim iLen As Integer
sResult = ""
iLen = 0
For i = 1 To Len(value)
If IsNumeric(Mid(value, i, 1)) Then
sResult = sResult & Mid(value, i, 1)
iLen = iLen + 1
Else
sResult = ""
iLen = 0
End If
If iLen = 5 Then Exit For
Next
If iLen = 5 Then
GET5DIGITS = Format(sResult, "00000")
Else
GET5DIGITS = "Error"
End If
End Function

Get substring until first numeric character

like my title already explained, I want to get a substring of a string (who contains a address) and I would like to have only the street..
It's not possible to only take the text (non-numeric) chars, because then the box will remain.
It's not possible to take substring till first space, because the streetname can contain a space..
For example 'developerstreet 123a' -> would like to have 'developerstreet'
The 'a' is a box number of the house, which I'm not interested in..
How can I do this in VB.NET?
Parsing addresses is notoriously difficult, so I caution you to make sure that you a very deliberate about the choices you make. I would strongly recommend reviewing the documentation provided by the postal service. If these are US addresses, you should start by looking at the USPS Publication 28.
However, to answer your specific question, you can find the index of the first numeric character in a string by using the Char.IsDigit method. You may also want to take a look at the Char.IsNumber method, but that's probably more inclusive than what you really want. For instance, this will get the index of the first numeric character in the input string:
Dim index As Integer = -1
For i As Integer = 0 to input.Length - 1
If Char.IsDigit(input(i)) Then
index = i
Exit For
End If
Next
However, for complex string parsing, like this, I would suggest learning Regular Expressions. Getting the non-numeric portion at the beginning of a string becomes trivial with RegEx:
Dim m As Match = Regex.Match(input, "^\D+")
If m.Success Then
Dim nonNumericPart As String = m.Value
End If
Here is the meaning of the regular expression in the above example:
^ - The matching string must start at the beginning of the line
\D - Any non-numeric character
+ - One or more times
try this:
Private Sub MyFormLoad(sender As Object, e As EventArgs) Handles Me.Load
Dim str As String = "developerstreet 123a"
Dim index As Integer = GetIndexOfNumber(str)
Dim substr As String = str.Substring(0, index)
MsgBox(substr)
End Sub
Public Function GetIndexOfNumber(ByVal str As String)
For n = 0 To str.Length - 1
If IsNumeric(str.Substring(n, 1)) Then
Return n
End If
Next
Return -1
End Function
output will be: developerstreet
text.Substring(0, text.IndexOfAny("0123456789"))

Comparing Strings - ASCII SPACE

What is the difference between doing this:
Dim strTest As String
If strTest > " " Then
End If
and this:
Dim strTest As String
If strTest <> "" Then
End If
I think that code sample 1 is comparing ASCII values (the ASCII code of a SPACE is 32). I have looked through the String section on MSDN but I am unable to find an answer.
Update
I am also confused about what happens here:
Dim strTest As String = "Test"
If strTest > " " Then
End If
The > (greater than) operator will test by alphabetical order or character code value order (depending on the Option Compare setting), whereas the <> (not equal) operator tests for equality. As long as the two strings are different at all, then <> will always evaluate to True. > will evaluate to true as long as the string on the right side of the operator comes after the first string alphabetically, or by character code value. Therefore:
Option Compare Text ' Compare strings alphabetically
...
Dim x As String = "Hello"
Dim y As String = "World"
If x <> y Then
' This block is executed because the strings are different
Else
' This block is skipped
End If
If x > y Then
' This block is skipped
Else
' This block is executed because "Hello" is less than "World" alphabetically
End If
In your question, however, you are comparing a null string variable (set to Nothing) with an empty string. In that case, the comparison operators treat a null variable as an empty string. Therefore, Nothing <> "" should evaluate to False because both sides of the operator are considered empty strings. An empty or null string should always be considered the first in the sort order, so Nothing > "Hello" should evaluate to False because an empty string comes before everything else. But, Nothing > "" should evaluate to False because they are both equal and therefore neither comes before or after the other.
To answer you final question, "Test" > " " will test if the letter T comes before or after a space. If Option Compare is set to Text, it will compare them alphabetically and should return True (this ultimately depends on the alphabetic sorting for your locale). If Option Compare is set to Binary, it will compare them based on their character code values. If they are ASCII strings, a space character has a lower value than a letter, like T, so it, also, should return True.