Dim keys1() As String = {"corrupt", "selfish", "power", "lying", "lies", "media"}
Dim terms1 As Integer = 0
Dim terms1string As String = ""
terms1string = Console.ReadLine()
For Each st As String In keys1
terms1 = terms1 + 1
Next
If terms1 < 2 Then
Console.WriteLine("yay!")
Else
Console.WriteLine("YouFail")
End If
Theres my code. I'd like it to be that if your string entered has more than two of those terms, then it writes "Yay"-- otherwise it writes "YouFail."
---update 8/29/12---
Function StageTwo(ByVal fname, ByVal lname, ByVal city)
Console.WriteLine("Describe the U.S. Government.")
Dim overall As Integer = 0
Dim keys1() As String = {"corrupt", "selfish", "power", "lying", "lies", "media"}
Dim terms1 As Integer = 0
Dim terms1string As String = ""
terms1string = Console.ReadLine()
For Each st As String In keys1
If InStr(terms1string, st) > 0 Then '<<<this line right here!
terms1 = terms1 + 1
End If
Next
If terms1 < 0 Then
Console.WriteLine("yay!")
overall = overall + 1
End If
Console.WriteLine()
Console.WriteLine("Describe the economic status in the U.S.")
Dim keys2() As String = {"broken", "backed", "failed", "skewed", "tilted", "99%", "rigged", "unfair"}
Dim terms2 As Integer = 0
Dim terms2string As String = ""
terms2string = Console.ReadLine()
For Each st As String In keys2
If InStr(terms2string, st) > 0 Then '<<<this line right here!
terms2 = terms2 + 1
End If
Next
If terms2 < 0 Then
Console.WriteLine("yay!")
overall = overall + 1
End If
If overall = 2 Then
Console.WriteLine()
Console.WriteLine("Enter a username.")
Dim username As String = ""
username = Console.ReadLine()
Console.WriteLine("Please wait.")
IsURLValid(username, overall)
Else
Console.WriteLine("Test Failed.")
End If
System.Threading.Thread.Sleep(2000)
End Function
That's my fresh code. Still not working, it's printing test failed after entering corrupt for the first one and broken for the second one. Help again?
Thanks so much guys.
Why so complicated? Just use Count:
Dim keys1() As String = {"corrupt", "selfish", "power", "lying", "lies", "media"}
Dim terms1string = Console.ReadLine()
Dim terms1 = keys1.Count(function(key) terms1string like "*" & key & "*")
If terms1 < 2 Then
Console.WriteLine("yay!")
Else
Console.WriteLine("YouFail")
End If
If you want to match the single words (foobar power lies are 2 matches, foobarpowerlies are 0 matches), you can use this line instead:
Dim terms1 = keys1.Count(function(key) terms1string.Split().Contains(key))
For completeness, here's a regex version:
' generous match ('foobarpowerlies' => 2 matches)
Dim pattern = String.Join("|", keys1)
Dim terms1 = Regex.Matches(terms1string, pattern).Count
or
' strict match using word boundaries ('foobarpowerlies' => 0 matches, but 'foobar power lies' => 2 matches)
Dim pattern = String.Join("|", keys1.Select(function(key) "\b" & key & "\b"))
Dim terms1 = Regex.Matches(terms1string, pattern).Count
Should "Austin Powers" match "power" and should "uncorrupt" match "corrupt"? Assuming "no"
Should "POWER" match "power"? Assuming "yes"
The safest way to do this is with Regex
Function WordCount(keys() As String, terms As String) As Integer
Dim pattern As String = "\b(" + Regex.Escape(keys(0))
For Each key In keys.Skip(1)
pattern += "|" + Regex.Escape(key)
Next
pattern += ")\b"
Return Regex.Matches("terms", pattern, RegexOptions.IgnoreCase).Count
End Function
Sub Main()
Dim keys1() As String = {"corrupt", "selfish", "power", "lying", "lies", "media"}
Dim count As Integer
count = WordCount(keys1, "lying son of a corrupt . . .") ' returns 2
count = WordCount(keys1, "Never caught lying and uncorrupt . . .") ' returns 1
End Sub
The Regex.Escape function ensures that any Regex specific characters in your keys will be escaped, and will not be treated as Regex commands.
The RegexOptions.IgnoreCase option tells it to do a case insensitive match.
The \b is a word boundry, so there must be a word boundary (space, punctuation, new line, start of string, end of string etc) before and after the match.
Putting the keys in this structure (key1|key2|key3) says it can match on key1 or key2 or key3
Hope this helps
I have something for you.
Your father's INSTR(). This is the weapon of a QuickBasic 4.5 hacker. Not as clumsy or random as a regex; an elegant weapon for a more civilized age.
Module Module1
Sub Main()
Dim keys1() As String = {"corrupt", "selfish", "power", "lying", "lies", "media"}
Dim terms1 As Integer = 0
Dim terms1string As String = ""
terms1string = Console.ReadLine()
For Each st As String In keys1
If InStr(terms1string, st) > 0 Then '<<<this line right here!
terms1 = terms1 + 1
End If
Next st
If terms1 < 2 Then
Console.WriteLine("yay!")
Else
Console.WriteLine("YouFail")
End If
Console.ReadKey()
End Sub
End Module
Perhaps too simplistic, but if you use IndexOf, you can change your For loop to:
If Not String.IsNullOrEmpty(terms1string) Then
For Each st As String In keys1
If terms1string.IndexOf(st) <> -1 Then
terms1 = terms1 + 1
End If
Next
End If
It's simplistic in that it doesn't tokenize the input... so words like "corruption" and "belies" will register a match. If you need exact matches, take a look at String.Split to get the input words, and then there are a number of algorithmic options to compare that list to your list of keys.
Related
The following code splits each lines into words and store the first words in each line into array list and the second words into another array list and so on. Then it selects the most frequent word from each list as correct word.
Module Module1
Sub Main()
Dim correctLine As String = ""
Dim line1 As String = "Canda has more than ones official language"
Dim line2 As String = "Canada has more than one oficial languages"
Dim line3 As String = "Canada has nore than one official lnguage"
Dim line4 As String = "Canada has nore than one offical language"
Dim wordsOfLine1() As String = line1.Split(" ")
Dim wordsOfLine2() As String = line2.Split(" ")
Dim wordsOfLine3() As String = line3.Split(" ")
Dim wordsOfLine4() As String = line4.Split(" ")
For i As Integer = 0 To wordsOfLine1.Length - 1
Dim wordAllLinesTemp As New List(Of String)(New String() {wordsOfLine1(i), wordsOfLine2(i), wordsOfLine3(i), wordsOfLine4(i)})
Dim counts = From n In wordAllLinesTemp
Group n By n Into Group
Order By Group.Count() Descending
Select Group.First
correctLine = correctLine & counts.First & " "
Next
correctLine = correctLine.Remove(correctLine.Length - 1)
Console.WriteLine(correctLine)
Console.ReadKey()
End Sub
End Module
My Question: How can I make it works with lines of different number of words. I mean that the length of each lines here is 7 words and the for loop works with this length (length-1). Suppose that line 3 contains 5 words.
EDIT: Accidentally had correctIndex where shortest should have been.
From what I can tell you are trying to see which line is the closest to the correctLine.
You can get the levenshtein distance using the following code:
Public Function LevDist(ByVal s As String,
ByVal t As String) As Integer
Dim n As Integer = s.Length
Dim m As Integer = t.Length
Dim d(n + 1, m + 1) As Integer
If n = 0 Then
Return m
End If
If m = 0 Then
Return n
End If
Dim i As Integer
Dim j As Integer
For i = 0 To n
d(i, 0) = i
Next
For j = 0 To m
d(0, j) = j
Next
For i = 1 To n
For j = 1 To m
Dim cost As Integer
If t(j - 1) = s(i - 1) Then
cost = 0
Else
cost = 1
End If
d(i, j) = Math.Min(Math.Min(d(i - 1, j) + 1, d(i, j - 1) + 1),
d(i - 1, j - 1) + cost)
Next
Next
Return d(n, m)
End Function
And then, this would be used to figure out which line is closest:
Dim correctLine As String = ""
Dim line1 As String = "Canda has more than ones official language"
Dim line2 As String = "Canada has more than one oficial languages"
Dim line3 As String = "Canada has nore than one official lnguage"
Dim line4 As String = "Canada has nore than one offical language"
Dim lineArray As new ArrayList
Dim countArray As new ArrayList
lineArray.Add(line1)
lineArray.Add(line2)
lineArray.Add(line3)
lineArray.Add(line4)
For i = 0 To lineArray.Count - 1
countArray.Add(LevDist(lineArray(i), correctLine))
Next
Dim shortest As Integer = Integer.MaxValue
Dim correctIndex As Integer = 0
For i = 0 To countArray.Count - 1
If countArray(i) <= shortest Then
correctIndex = i
shortest = countArray(i)
End If
Next
Console.WriteLine(lineArray(correctIndex))
I am developing a program where you can input a sentence and then search for a word. The program will then tell you at which positions this word occurs. I have written some code but do not know how to continue.
Module Module1
Sub Main()
Dim Sentence As String
Dim SentenceLength As Integer
Dim L As Integer = 0
Dim LotsofText As String = Console.ReadLine
Console.WriteLine("Enter your word ") : Sentence = Console.ReadLine
For L = 1 To LotsofText.Length
If (Mid(LotsofText, L, 1)) = " " Then
End If
L = L + 1
Dim TextCounter As Integer = 0
Dim MainWord As String = Sentence
Dim CountChar As String = " "
Do While InStr(MainWord, CountChar) > 0
MainWord = Mid(MainWord, 1 + InStr(MainWord, CountChar), Len(MainWord))
TextCounter = TextCounter + 1
'Text = TextCounter + 2
' Console.WriteLine(Text)
Loop
Console.WriteLine(TextCounter)
Console.Write("Press Enter to Exit")
Console.ReadLine()
End Sub
End Module
Transform this piece of code from C# to Visual Basic. match.Index will indicate the position of the given word.
var rx = new Regex("your");
foreach (Match match in rx.Matches("This is your text! This is your text!"))
{
int i = match.Index;
}
To find only words and not sub-strings (for example to ignore "cat" in "catty"):
Dim LotsofText = "catty cat"
Dim Sentence = "cat"
Dim pattern = "\b" & Regex.Escape(Sentence) & "\b"
Dim matches = Regex.Matches(LotsofText, pattern)
For Each m As Match In matches
Debug.Print(m.Index & "") ' 6
Next
If you want to find sub-strings too, you can remove the "\b" parts.
If you add this function to your code:
Public Function GetIndexes(ByVal SearchWithinThis As String, ByVal SearchForThis As String) As List(Of Integer)
Dim Result As New List(Of Integer)
Dim i As Integer = SearchWithinThis.IndexOf(SearchForThis)
While (i <> -1)
Result.Add(i)
i = SearchWithinThis.IndexOf(SearchForThis, i + 1)
End While
Return Result
End Function
And call the function in your code:
Dim Indexes as list(of Integer) = GetIndexes(LotsofText, Sentence)
Now GetIndexes will find all indexes of the word you are searching for within the sentence and put them in the list Indexes.
I´m trying to write a parser that reads large files, try to locate X Y Z values on lines that can contain more registers than only X Y Z (Like M codes and other commands to drive CNC machines).
I was successful in reading the code and separating data from each line. Now I´m stuck in a function that is supposed to analyze this treated block and look up for X Y and Z coordinates, not necessarily in this order, not necessarily containing all 3 axes.
The good news is that the axis name always preceeds the value of the given axis, so even if the line may have XYZ out of order (ZYX or YZX for example), or just X and Y without Z, the letter of the axis is always preceeding the value.
I need to extract the value of each axis and treat it, and the save it back. I can do the treat and save it back, but I´m clueless about how I can write a function that can parse X Y and Z even if they are out of order or with a missing register (i.e., Z is not present in the block, or Y, or X).
I only want to extract XYZ values in the string strNewLine passed to the function ParseAndChangeNCBlocks, and ignore everything else in the line.
This is my code:
Imports System.IO
Module Module1
Public DebugMode As Boolean = True
Sub Main()
Dim path As String = "C:\8888.nc"
' This text is added only once to the file.
If File.Exists(path) = False Then
' Create a file to write to.
Dim createText() As String = {"Hello", "And", "Welcome"}
File.WriteAllLines(path, createText)
End If
' This text is always added, making the file longer over time
' if it is not deleted.
Dim appendText As String = "This is extra text" + Environment.NewLine
File.AppendAllText(path, appendText)
' Open the file to read from.
Dim NCProgram() As String = File.ReadAllLines(path)
Dim NCBlock As String
For Each NCBlock In NCProgram
Console.WriteLine(CleanUpAndSeparateBlocks(NCBlock))
Next
End Sub
Function CleanUpAndSeparateBlocks(ByVal NCBlock As String) As String
Dim strBlockLength As Integer = 0 'Comprimento do bloco
Dim strNewLine As String = "" 'Linha tratada
Dim strMotionText = "" 'Parte anterior ao comentário
Dim strCommentText = "" 'Comentário do bloco
Dim intCommentStartIndex As Integer = 0 'Index inicial do comentário
Dim intCommentEndIndex As Integer = 0 'Index final do comentário
Dim intCommentLength As Integer = 0 'Comprimento do comentário
strNewLine = NCBlock.Trim 'Remove blanks esq/dir
strNewLine = strNewLine.ToUpper 'Converte pra maiúsculas
intCommentStartIndex = strNewLine.IndexOf("(") 'Armazena o início do comentário
intCommentEndIndex = strNewLine.IndexOf(")") 'Armazena o fim do comentário
If intCommentStartIndex > -1 And intCommentEndIndex > -1 Then 'Se um comentário for detectado
strBlockLength = strNewLine.Length 'Captura o comprimento do bloco
strCommentText = strNewLine.Remove(0, intCommentStartIndex) 'Remove a string anterior ao seu início
strCommentText = strCommentText.Trim 'Remove blanks esq/dir
strMotionText = strNewLine.Remove(intCommentStartIndex, strBlockLength - intCommentStartIndex) 'Separa a parte anterior ao comentário
strMotionText = strMotionText.Trim 'Remove blanks esq/dir
strMotionText = strMotionText.Replace(Chr(32), "") 'Remove blanks do meio da string
strNewLine = strMotionText + Chr(32) + strCommentText 'Forma o novo bloco
If DebugMode = True Then 'Se depuração estiver ativa
MsgBox(strNewLine) 'Exibe a nova linha
End If
Else 'Bloco não contém comentários
strNewLine = strNewLine.Replace(Chr(32), "") 'Remove blanks do meio da string
End If
ParseAndChangeNCBlocks(strNewLine) 'Converte coordenadas para interpolação cilíndrica
Return strNewLine
End Function
Function ParseAndChangeNCBlocks(ByVal NCBlock As String) As String
Dim XCoord As Double = 0
Dim YCoord As Double = 0
Dim ZCoord As Double = 0
Return NCBlock
End Function
End Module
In the end of the funcion CleanUpAndSeparateBlocks I call ParseAndChangeNCBlocks. The last is the function where I´m supposed to analyze the string that has been passed to the function, and start the extraction of each axis.
I thought about using this to extract each value: Found it here: VB.net Set x,y,z values from text file into separate arrays
Dim values As String() = line.Split(","c)
Dim x As Integer = Integer.Parse(values(0))
Dim y As Integer = Integer.Parse(values(1))
Dim z As Integer = Integer.Parse(values(2))
However, this solution assumes that XYZ are always in this order, and that they are not preceded by the axis name, which in my case always occur, but the axes may be presented out of order or even be absent from the line.
Here some test data to be used within "C:\8888.nc"
%
o8888(usinagem helice)
g00g21g40g80g99
g49
g69.1
m05
m46
m246
m45
n10 g28u0.
n20 g28w0.
n30 g28h0.
n40 g330
n50 (#5222=0)
n60 g7.1y0.
n70 m69
n80 m46
n90 g98g18
n100 m45
n110 (desbasta perfil - parte 1)
n120 t1025
n130 g361b0d0
n140 g43h25.
n150 g54
n160 s3714m13
n170 g01z440.#0.x13.258y-276.689f10000.
n180 g19w0h0
n190 g1 y-276.689
n200 g7.1y188.
n210 g01z376.
n220 goto 2843850 (jump to contour finish - using cutcom and cylindrical interpolation)
n230 g03 x7.809 y-271.766 r87.496
n240 g01 x7.804 y-271.758 f1485.
n250 y-271.756
n260 x7.846 y-271.75
n270 x7.902 y-271.743
n280 x7.974 y-271.734
n290 x8.064 y-271.725
n300 x8.175 y-271.713
n310 x8.311 y-271.701
n320 x8.477 y-271.688
n330 x8.68 y-271.673
n340 x8.927 y-271.656
n350 x9.232 y-271.639
n360 x9.613 y-271.62
n370 x10.097 y-271.6
n380 x10.69 y-271.581
n390 x11.284 y-271.566
n400 x11.879 y-271.554
n410 x12.055 y-271.551
n420 x12.449 y-271.553
n430 x12.837 y-271.573
n440 x13.207 y-271.61
n450 x13.55 y-271.664
n460 x13.856 y-271.731
n470 x14.118 y-271.812
n480 x14.328 y-271.903
n490 x14.48 y-272.002
n500 x14.571 y-272.107
n510 g03 x13.711 y-272.547 r1.606 f10000.
n520 x7.804 y-271.758 r4.1
n530 g01 x7.78 y-271.714 f1485.
n540 z100. x7.779 y-271.711
n550 x7.835 y-271.7
n560 x7.898 y-271.687
n570 x7.972 y-271.674
n580 Z200. x8.052 y-271.659
I only want to extract the X, Y, Z values of each line, in whatever the order or combination (XYZ, or Z, or YX, or Y, etc) they appear. Can someone shed some light in how I can structure the function ParseAndChangeNCBlocks to do that?
Many thanks!
This is easy to do with regular expressions. You just need to work out a regex which will match a number, then precede it with x, y, or z as needed:
Imports System.Text.RegularExpressions
Module Module1
Function ExtractAndOrderXYZ(s As String) As String
Dim num = "([+-]?[0-9.]+)" ' regex to match a number
Dim xMatch = Regex.Match(s, "x" & num, RegexOptions.IgnoreCase)
Dim yMatch = Regex.Match(s, "y" & num, RegexOptions.IgnoreCase)
Dim zMatch = Regex.Match(s, "z" & num, RegexOptions.IgnoreCase)
Dim orderedString = ""
If xMatch.Success Then
orderedString = xMatch.Captures(0).Value
End If
If yMatch.Success Then
orderedString &= yMatch.Captures(0).Value
End If
If zMatch.Success Then
orderedString &= zMatch.Captures(0).Value
End If
Return orderedString
End Function
Sub Main()
' Following line outputs x13.258y-276.689z440.
Console.WriteLine(ExtractAndOrderXYZ("n170 g01z440.#0.x13.258y-276.689f10000."))
' Following line outputs y-276.689
Console.WriteLine(ExtractAndOrderXYZ("n190 g1 y-276.689"))
' Following line outputs x7.809y-271.766
Console.WriteLine(ExtractAndOrderXYZ("n230 g03 x7.809 y-271.766 r87.496"))
Console.ReadLine()
End Sub
End Module
In the regex ([+-]?[0-9.]+), the parentheses indicate what to capture. [+-]? means an optional sign, [0-9.]+ means one-or-more digit or decimal point.
try this to get X value from a line. you can do the same for y and z
function getX(byval line as string) as string
Dim val as String = ""
if(line.indexOf("X") >= 0)
val = line.subString(line.indexOf("X") + 1)
val = val.subString(0, val.indexOf(" ")
end if
return val
end function
you can do it like this. comment in code.
Function ParseAndChangeNCBlocks(ByVal NCBlock As String) As String
Dim XCoord As Double = 0
Dim YCoord As Double = 0
Dim ZCoord As Double = 0
Dim values As String() = NCBlock.Split(" "c)
'iterate through each item and check what char it starts with
For Each value As String In values
If value.StartsWith("x") Then
XCoord = Val(value.Substring(1))
ElseIf value.StartsWith("y") Then
YCoord = Val(value.Substring(1))
ElseIf value.StartsWith("z") Then
ZCoord = Val(value.Substring(1))
End If
Next
'Do all your calculation here for the x y z
'don't know what return you want
'this just puts it back in the order
Return String.Format("x{0} y{1} z{2}", XCoord, YCoord, ZCoord)
End Function
Note: if you expect upper and lower case letter for xyz then you should use comparison like the following.
value.StartsWith("x", StringComparison.InvariantCultureIgnoreCase)
I am trying to write an encryption program. The problem I am facing is that I am converting the text to ascii and then adding on the offset. However when it goes past the letter 'z' I want it to warp back to 'a' and go from there.
Sub enc()
Text = TextBox1.Text
finalmessage = ""
letters = Text.ToCharArray
offset = ComboBox1.SelectedItem
For x = LBound(letters) To UBound(letters)
finalmessage = finalmessage + Chr(Asc(letters(x)) + offset)
Next
TextBox2.Text = finalmessage
End Sub
I guess to make it easy to decode afterwards, you should to it somewhat in the line of base64 encoding, first encoding everything to a normalized binary string, then encode in the range you want (since using binary, it has to be something that fits with 2^X).
To match your range, i used a baseset of 32, and a simple encoding decoding example (a bit more verbose that it should be, perhaps)
Module Module1
Dim encodeChars As String = "abcdefghijklmnopqrstuvwxyzABCDEF" ' use 32 as a base
Function Encode(text As String) As String
Dim bitEncoded As String = ""
Dim outputMessage As String = ""
For Each ch As Char In text.ToCharArray()
Dim i As Integer = Convert.ToByte(ch)
bitEncoded &= Convert.ToString(i, 2).PadLeft(8, "0"c)
Next
While bitEncoded.Length Mod 5 <> 0
bitEncoded &= "0"
End While
For position As Integer = 0 To bitEncoded.Length - 1 Step 5
Dim range As String = bitEncoded.Substring(position, 5)
Dim index As Integer = Convert.ToInt32(range, 2)
outputMessage &= encodeChars(index).ToString()
Next
Return outputMessage
End Function
Function Decode(encodedText As String) As String
Dim bitEncoded As String = ""
Dim outputMessage As String = ""
For Each ch In encodedText
Dim index As Integer = encodeChars.IndexOf(ch)
If index < 0 Then
Throw New FormatException("Invalid character in encodedText!")
End If
bitEncoded &= Convert.ToString(index, 2).PadLeft(5, "0"c)
Next
' strip the extra 0's
While bitEncoded.Length Mod 8 <> 0
bitEncoded = bitEncoded.Substring(0, bitEncoded.Length - 1)
End While
For position As Integer = 0 To bitEncoded.Length - 1 Step 8
Dim range As String = bitEncoded.Substring(position, 8)
Dim index As Integer = Convert.ToInt32(range, 2)
outputMessage &= Chr(index).ToString()
Next
Return outputMessage
End Function
Sub Main()
Dim textToEncode As String = "This is a small test, with some special characters! Just testing..."
Dim encodedText As String = Encode(textToEncode)
Dim decodedText As String = Decode(encodedText)
Console.WriteLine(textToEncode)
Console.WriteLine(encodedText)
Console.WriteLine(decodedText)
If Not String.Equals(decodedText, textToEncode) Then
Console.WriteLine("Encoding / decoding failed!")
Else
Console.WriteLine("Encoding / decoding completed succesfully!")
End If
Console.ReadLine()
End Sub
End Module
this then gives the following output?
This is a small test, with some special characters! Just testing...
krugsCzanfzsayjaonwwcBdmebAgkCBufqqhoAlunaqhgBBnmuqhgCdfmnuwcBbamnugcCtbmnAgkCtteeqeuDltoqqhizltoruwCzzofyxa
This is a small test, with some special characters! Just testing...
Encoding / decoding completed succesfully!
I have string "ololo123".
I need get position of first digit - 1.
How to set mask of search ?
Here is a lightweight and fast method that avoids regex/reference additions, thus helping with overhead and transportability should that be an advantage.
Public Function GetNumLoc(xValue As String) As Integer
For GetNumLoc = 1 To Len(xValue)
If Mid(xValue, GetNumLoc, 1) Like "#" Then Exit Function
Next
GetNumLoc = 0
End Function
Something like this should do the trick for you:
Public Function GetPositionOfFirstNumericCharacter(ByVal s As String) As Integer
For i = 1 To Len(s)
Dim currentCharacter As String
currentCharacter = Mid(s, i, 1)
If IsNumeric(currentCharacter) = True Then
GetPositionOfFirstNumericCharacter = i
Exit Function
End If
Next i
End Function
You can then call it like this:
Dim iPosition as Integer
iPosition = GetPositionOfFirstNumericCharacter("ololo123")
Not sure on your environment, but this worked in Excel 2010
'Added reference for Microsoft VBScript Regular Expressions 5.5
Const myString As String = "ololo123"
Dim regex As New RegExp
Dim regmatch As MatchCollection
regex.Pattern = "\d"
Set regmatch = regex.Execute(myString)
MsgBox (regmatch.Item(0).FirstIndex) ' Outputs 5
I actually have that function:
Public Function GetNumericPosition(ByVal s As String) As Integer
Dim result As Integer
Dim i As Integer
Dim ii As Integer
result = -1
ii = Len(s)
For i = 1 To ii
If IsNumeric(Mid$(s, i, 1)) Then
result = i
Exit For
End If
Next
GetNumericPosition = result
End Function
You could try regex, and then you'd have two problems. My VBAfu is not up to snuff, but I'll give it a go:
Function FirstDigit(strData As String) As Integer
Dim RE As Object REMatches As Object
Set RE = CreateObject("vbscript.regexp")
With RE
.Pattern = "[0-9]"
End With
Set REMatches = RE.Execute(strData)
FirstDigit = REMatches(0).FirstIndex
End Function
Then you just call it with FirstDigit("ololo123").
If speed is an issue, this will run a bit faster than Robs (noi Rob):
Public Sub Example()
Const myString As String = "ololo123"
Dim position As Long
position = GetFirstNumeric(myString)
If position > 0 Then
MsgBox "Found numeric at postion " & position & "."
Else
MsgBox "Numeric not found."
End If
End Sub
Public Function GetFirstNumeric(ByVal value As String) As Long
Dim i As Long
Dim bytValue() As Byte
Dim lngRtnVal As Long
bytValue = value
For i = 0 To UBound(bytValue) Step 2
Select Case bytValue(i)
Case vbKey0 To vbKey9
If bytValue(i + 1) = 0 Then
lngRtnVal = (i \ 2) + 1
Exit For
End If
End Select
Next
GetFirstNumeric = lngRtnVal
End Function
An improved version of spere's answer (can't edit his answer), which works for any pattern
Private Function GetNumLoc(textValue As String, pattern As String) As Integer
For GetNumLoc = 1 To (Len(textValue) - Len(pattern) + 1)
If Mid(textValue, GetNumLoc, Len(pattern)) Like pattern Then Exit Function
Next
GetNumLoc = 0
End Function
To get the pattern value you can use this:
Private Function GetTextByPattern(textValue As String, pattern As String) As String
Dim NumLoc As Integer
For NumLoc = 1 To (Len(textValue) - Len(pattern) + 1)
If Mid(textValue, NumLoc, Len(pattern)) Like pattern Then
GetTextByPattern = Mid(textValue, NumLoc, Len(pattern))
Exit Function
End If
Next
GetTextByPattern = ""
End Function
Example use:
dim bill as String
bill = "BILLNUMBER 2202/1132/1 PT2200136"
Debug.Print GetNumLoc(bill , "PT#######")
'Printed result:
'24
Debug.Print GetTextByPattern(bill , "PT#######")
'Printed result:
'PT2200136