Array text manipulation - arrays

So, I've managed to populate an array with the names of directories, what i need to do now is remove certain parts of the directory names. this is what most of my array look like
F:\Users\Killu\AppData\Local\osu!\Songs\82734 Sakakibara Yui - Nyanderful!
what i need to remove is "F:\Users\Killu\AppData\Local\osu!\Songs\" and then everything after the number. so i would just be left with the various number in my array, the numbers do vary in length from 1 to 7 digits

Use split then connect them together again
Dim Result as string
Dim splitdir() as string = Split("F:\Users\Killu\AppData\Local\osu!\Songs\82734 Sakakibara Yui - Nyanderful!", "\")
Dim x as integer
For i as integer = 0 to 99
For j as integer = 0 to 9
If splitdir(i).substring(0,1) = j
x = i
i = 99
End if
Next
Next
For i as integer = x to splitdir.length - 1
Result += splitdir(i)
Next
Or if the numbers are always in the last part of the directory
Dim Result as string
Dim splitdir() as string = Split("F:\Users\Killu\AppData\Local\osu!\Songs\82734 Sakakibara Yui - Nyanderful!", "\")
Dim x as integer
Result = splitdir(splitdir.length - 1)
I was typing this on my ipad so im sorry if i made some typos/mistakes

Related

How to speed up extracting numbers from chemical formula

I have been using some useful VBA code by PEH that uses regular expression to extract the number of instances of a specific element in a chemical formula, see: https://stackoverflow.com/a/46091904/17194644
It works well, but everything slows down when I use the function hundreds of times in one worksheet. I was wondering if this might be due to the time it takes VBA to read/write values from/to the cells, so I created an array function (based on the regex code by PEH) to see if it would speed things up, see below. The function works and is quicker but can still slow things down when dealing with hundreds of values, and I cannot get the second part to work that finds multiplies elements within parenthesis. Any thoughts on how to improve further?
Function CountElements(ChemFormulaRange As Variant, ElementRange As Variant) As Variant
'define variables
Dim RetValRange() As Long
Dim RetVal As Long
Dim ChemFormula As String
Dim npoints As Long
Dim i As Long
Dim mpoints As Long
Dim j As Long
' Convert input ranges to variant arrays
If TypeName(ChemFormulaRange) = "Range" Then ChemFormulaRange = ChemFormulaRange.Value
If TypeName(ElementRange) = "Range" Then ElementRange = ElementRange.Value
'parameter
npoints = UBound(ChemFormulaRange, 1) - LBound(ChemFormulaRange, 1) + 1
mpoints = UBound(ElementRange, 2) - LBound(ElementRange, 2) + 1
'dimension arrays
ReDim RetValRange(1 To npoints, 1 To mpoints)
'calculate all values
For j = 1 To mpoints
Element = ElementRange(1, j)
For i = 1 To npoints
RetVal = 0
ChemFormula = ChemFormulaRange(i, 1)
Call ChemRegex(ChemFormula, Element, RetVal)
RetValRange(i, j) = RetVal
Next i
Next j
'output answer
CountElements = RetValRange
End Function
Private Sub ChemRegex(ChemFormula, Element, RetVal)
Dim regEx As New RegExp
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
End With
'first pattern matches every element once
regEx.Pattern = "([A][cglmrstu]|[B][aehikr]?|[C][adeflmnorsu]?|[D][bsy]|[E][rsu]|[F][elmr]?|[G][ade]|[H][efgos]?|[I][nr]?|[K][r]?|[L][airuv]|[M][cdgnot]|[N][abdehiop]?|[O][gs]?|[P][abdmortu]?|[R][abefghnu]|[S][bcegimnr]?|[T][abcehilms]|[U]|[V]|[W]|[X][e]|[Y][b]?|[Z][nr])([0-9]*)"
Dim Matches As MatchCollection
Set Matches = regEx.Execute(ChemFormula)
Dim m As Match
For Each m In Matches
If m.SubMatches(0) = Element Then
RetVal = RetVal + IIf(Not m.SubMatches(1) = vbNullString, m.SubMatches(1), 1)
End If
Next m
'second patternd finds parenthesis and multiplies elements within
' regEx.Pattern = "(\((.+?)\)([0-9])+)+?"
' Set Matches = regEx.Execute(ChemFormula)
' For Each m In Matches
' RetVal = RetVal + ChemFormula(m.SubMatches(1), Element) * (m.SubMatches(2) - 1) '-1 because all elements were already counted once in the first pattern
' Next m
End Sub
If you are using Office 365, then you do not need VBA. A formula can achieve what you want and I think it would be faster.
=TRIM(TEXTJOIN("",TRUE,IFERROR((MID(A1,ROW(INDIRECT("1:"&LEN(A1))),1)*1)," ")))
Note: If you still need a VBA solution then remember you can enter the above formula in the entire range in one go and then convert it to values.
rng.Formula = "=TRIM(TEXTJOIN("""",TRUE,IFERROR((MID(A1,ROW(INDIRECT(""1:""&LEN(A1))),1)*1),"" "")))"
rng.Value = rng.Value
The slowest part of your ChemRegex routine is creating the RegExp object.
If all your cells are passed to CountElements as a pair of large areas move the code that creates the RegExp object and applies a few properties from ChemRegex to CountElements, and pass the RegExp reference from CountElements to ChemRegex.
Or, if you are calling CountElements as say a UDF in multiple cells, declare RegExp at module level
Private RegEx as RegExp
In CountElements...
If RegEx is Nothing Then
Set RegEx = New RegExp
' apply the properties
End If
' code
' and pass RegEx to ChemRegex
Call ChemRegex(ChemFormula, Element, RetVal, RegEx)
Isolate all numbers in chemical formula
Just for the sake of the art an alternative to Siddharth 's approach, where I demonstrate how to use Match() comparing
an array of each formula character|digit in the given string with
an array of all regular digits.
This allows to identify array elements (here: digits) based on their position. So this demo might be also helpful to solve similar requirements. - I don't pretend this to be a better or faster way.
Function ChemNo(ByVal s As String) As Variant
'Purp: return array of found character positions in chars string
'Note: (non-findings show Error 2042; can be identified by IsError + Not IsNumeric)
Dim digits
digits = String2Arr("1234567890")
'get any digit position within array digits ' note: zero position returns 10
Dim tmp
tmp = Application.Match(String2Arr(s), digits, 0)
'check for digits in a loop through tmp
Dim i As Long, ii As Long
For i = 1 To UBound(tmp)
If IsNumeric(tmp(i)) Then ' found digit
tmp(i) = tmp(i) Mod 10 ' get digtis including zeros
If IsNumeric(tmp(i - 1)) Then ' check preceding digit
tmp(i) = 10 * tmp(i - 1) + tmp(i) ' complete number
tmp(i - 1) = "!" ' mark former digit
End If
Else
tmp(i) = "!" ' mark non-numeric element
End If
Next i
ChemNo = Filter(tmp, "!", False) ' delete marked elements
End Function
Help function String2Arr()
Assigns an array of single characters after atomizing a string input:
Function String2Arr(ByVal s As String) As Variant
'Purp: return array of all single characters in a string
'Idea: https://stackoverflow.com/questions/13195583/split-string-into-array-of-characters
s = StrConv(s, vbUnicode)
String2Arr = Split(s, vbNullChar, Len(s) \ 2)
End Function
If you want to use the function as tabular input profiting from the newer dynamic features in Excel, you may enter it as user defined function e.g. in cell B1: =ChemNo(A1) displaying each number horizontally in as so called spill range. Using older versions, I suppose you'd need a CSE entry (Ctrl↑┘) to mark it as {array} formula.

How to store ranges of numbers separted by comma and hyphen in an array?

I have to store numbers contained in a string into arrays in a special way.
The string contains comma and hyphen.
The comma-separated numbers should be stored individually
Numbers separated by a hyphen should be stored as a range of values.
For example, my string is:
Reg. No 556002,556010-556013,556039 Cancelled
The array should store the numbers as:
(0) 556002 - Single
(1) 556010 ---------|
(2) 556011 Range of
(3) 556012 values
(4) 556013 ---------|
(5) 556039 - Single
I tried the following code:
Dim i, str
Dim array() As Char = str.ToCharArray()
Dim rnoarray() As Integer = New Integer() {}
Dim rno = ""
Dim nosta As Boolean
Dim j = 0
str = "Reg. No 556002,556010-556013,556039 Cancelled"
nosta = False
ReDim rnoarray(Len(str) + 2)
For i = 0 To Len(str)-1
If IsNumeric(array(i)) Then
rno = rno & array(i)
nosta = True
Else
If nosta = True Then
rnoarray(j) = Val(rno)
j = j + 1
nosta = False
rno = ""
End If
End If
Next
For x = 0 To j - 1
MessageBox.Show(rnoarray(x))
Next
But the result only includes four numbers:
556002
556010
556013
556039
Some steps to consider:
Extract the numbers from the input string, preserving the hyphen when present
Verify whether one of the parts contains a hyphen:
In this case, Split() the string into two parts
Convert to Integer the two parts
Take the minimum and the maximum values
Create a range of numbers between the minimum and maximum values
Add the range of numbers to a List(Of Integer)
Convert strings that do not contain a hyphen to Integer
Add the converted numbers to a List(Of Integer)
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text.RegularExpressions
Dim input = "Reg. No 556002,556010-556013,556039 Cancelled"
Dim numbers As New List(Of Integer)
Dim matches = Regex.Matches(input, "\d+-*\d*").OfType(Of Match)
For Each m As Match In matches
If m.Value.Contains("-") Then
Dim parts = m.Value.Split("-"c).Select(Function(s) Integer.Parse(s)).ToArray()
Dim nStart As Integer = Math.Min(parts(0), parts(1))
Dim nEnd As Integer = Math.Max(parts(0), parts(1))
numbers.AddRange(Enumerable.Range(nStart, nEnd - nStart + 1))
Else
numbers.Add(Integer.Parse(m.Value))
End If
Next
Without Regular Expression (assuming the input string format presented here matches the original):
For Each part As String In input.Split(","c)
If part.Contains("-") Then
Dim nValues = part.Split("-"c).Select(Function(s) Integer.Parse(s)).ToArray()
Dim nStart As Integer = Math.Min(nValues(0), nValues(1))
Dim nEnd As Integer = Math.Max(nValues(0), nValues(1))
numbers.AddRange(Enumerable.Range(nStart, nEnd - nStart + 1))
Else
Dim sValue = String.Concat(part.Where(Function(c) Char.IsDigit(c)))
numbers.Add(Integer.Parse(sValue))
End If
Next

Making a binary to decimal converter, but need to convert a char array to a integer array

I need to create a code that converts any binary number (up to 8 digits) into the decimal counterpart.
So i have created most of the program but i have one problem, this is that i have used a ToCharArray to split the string of numbers entered into the individual elements of an array. But then i have to use them number for arithmetic, - but for that they need to be in an integer array.
Dim array(7) As Integer
Dim num As String
Dim i As Integer = 0
Dim x As Integer = 0
Dim y As Integer = 1
Dim dec As Integer = 0
console.writeline("Enter an 8-Digit binary string")
num = console.readline()
num.ToCharArray(array)
array.Reverse(array)
For i = 0 To 7
dec = dec + array(x) * 1 * y
x = x + 1
y = y * 2
Next
console.write(dec)
console.read()
(Sorry i didn't know which parts would be helpful or not, so heres what ive got so far)
Make your life easier and take advantage of the convert in vb.net so be something very simple like this
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim binary As String = "11010110"
Console.WriteLine(ToDecimal(binary))
End Sub
Function ToDecimal(input As String) As Integer
Dim i As Integer = Convert.ToInt32(input, 2)
Return i
End Function

Read integers separated by commas from Text file in VB.NET Console Application

I have to write a VB.NET Console Application in Visual Studio which will read Integers from a Text (.txt) file and put them into an Array.
So far I have tried this:
Dim arr(100) As Integer
Dim stream_reader As New StreamReader("Data.txt")
For j As Integer = 0 To 100 - 1
arr(j) = Integer.Parse(stream_reader.ReadLine())
Next j
stream_reader.Close()
Console.ReadLine()
But as soon as I run the program it throws an exception with the message:
"FormatException was unhandled."
Contents of the text file (Data.txt) are in this format :-
11,6,7,1,2,5,4,3,9,8,0
If the integers are separated by commas, the StreamReader would be of no use. You can use the String.Split() method like this:
Dim arr(100) As Integer
Dim temp = File.ReadAllText("Data.txt").Split(","C)
For j As Integer = 0 To 100 - 1
arr(j) = Integer.Parse(temp(j))
Next j
Note - If you specify 100 - 1 in the For Loop, you will need to ensure that the text file contains 100 integers. Otherwise, you can first evaluate Dim temp = File.ReadAllText("Data.txt").Split(","C) and then use the temp.Length - 1 in both the loop and as the capacity of the array.

Array go out of bounds in VB

I'm currently working on a program that will convert a string into "combined integer" (namely: from a string, it will be splitted into two characters at a time and then each character in each group will be converted into ASCII number. Then, the first character is multiplied by 256 (shift 8 bit to the left) and add second character. It must not eliminate/forget any character inside the string
Here is when the trouble really begin: it threw IndexOutOfRangeException
Dim input As String = TextBox1.Text.PadLeft(1)
Dim charArr As Char() = input.ToCharArray
Dim intGroup As UShort
Dim strout As String = ""
For index = 0 To charArr.Length - 2 Step 2
Dim i = index
Dim a = charArr(i)
Dim b = charArr(i + 1)
intGroup = CByte(AscW(a)) * 256 + CByte(AscW(b))
strout = strout + CStr(intGroup) + " "
Next
MsgBox(strout)
My guess was that I modify the index inside the loop which is 'forbidden'.
Any possible solution??
Thanks
I would do something like this but I don't know how you want to deal with odd length strings:
For index = 0 To charArr.Length - 1 Step 2
Dim a = charArr(index)
Dim b = If(index=charArr.Length - 1, _
<something to use for odd length strings>, _
charArr(index + 1))
intGroup = CByte(AscW(a)) * 256 + CByte(AscW(b))
strout = strout + CStr(intGroup) + " "
Next
I don't know what you want to use, especially if you bear in mind that .NET strings (unlike, say, C strings) can perfectly well contain a character with ascii code 0, so just using 0 may leave you with ambiguous data, depending on how you're using this string that you're constructing.
But basically, it comes down to you needing to do some special handling for odd length strings, and no magic manipulation of the for loop parameters will avoid that fact - you either deal with them in the loop (as above) or use a shorter loop (.Length - 2) and perform a length check afterwards and deal with the final character that you missed in the loop separately.
For index = 0 To input.Length - 2 step 2
array its zero based, so if the lenght = n, last element is arr[n-1].
for handle only odds element, the last element its arr[n-2].

Resources