Most people ask how to get the characters from a string, which can be done by Mid(). I am trying to assign a string character by character in VBA code. The characters to be assigned depend on some calculated results.
I do not want to use string concatenation to form the string.
I have searched the web, but the posted solution, strName.Chars(i) (e.g., at MS development network), is not recognized in my 2007 Access VBA.
Thanks
You can use Mid to set values, too.
Sub showMidExample()
Dim s As String
s = "aaaaa"
Dim i As Integer
For i = 1 To Len(s)
Mid(s, i) = "n"
Debug.Print s
Next i
End Sub
This prints out
naaaa
nnaaa
nnnaa
nnnna
nnnnn
Which is what you are looking for.
Since no working answer is posted. I assume that cannot be done in VBA and I have to use concatenation to form the string although that is cumbersome in my case.
Related
I have the following strings from which I need to extract 6 digit numbers. Since these strings are generated by another software, they occur interchangeably and I cannot control it. Is there any one method that would extract both 6-digit numbers from each of these strings?
Branch '100235 to 100236 Ckt 1' specified in table 'East Contingency' for record with primary key = 21733 was not found in branch or transformer data.
Loadflow branch ID '256574_701027_1' defined in supplemental branch table was not found in branch or transformer input.
Transmission element from bus number 135415 to bus number 157062 circuit ID = 1 defined for corridor 'IESO-NYISO' was not found in input data
I don't know VBA, but I can learn it if it means I can get the 6 digit numbers using a single method.
thanks
I have been using LEFT(), RIGHT() & MID() previously, but it means manually applying the appropriate formula for individual string.
If you have Microsoft 365, you can use this formula:
=LET(arr,TEXTSPLIT(SUBSTITUTE(SUBSTITUTE(A1,"'"," "),"_"," ")," "),
FILTER(arr,ISNUMBER(-arr)*(LEN(arr)=6)))
Thanks to #TomSharpe for this shorter version, using an array constant within TEXTSPLIT to add on possible delimiters.
=LET(arr,TEXTSPLIT(A1,{"_"," ",","," ","'"}),FILTER(arr,(LEN(arr)=6)*ISNUMBER(-arr)))
Data
Output
An alternative is:
=LET(ζ,MID(A1,SEQUENCE(,LEN(A1)-5),6),ξ,MID(ζ,SEQUENCE(6),1),FILTER(ζ,MMULT(SEQUENCE(,6,,0),1-ISERR(0+ξ))=6))
A couple more suggestions (if you need them):
(1) Replacing all non-digit characters with a space then splitting the resulting string:
=LET(numbers,TEXTSPLIT(TRIM(REDUCE("",MID(A1,SEQUENCE(1,LEN(A1)),1),LAMBDA(a,c,IF(is.digit(c),a&c,a&" "))))," "),FILTER(numbers,LEN(numbers)=6))
Here I've defined a function is.digit as
=LAMBDA(c, IF(c = "", FALSE, AND(CODE(c) > 47, CODE(c) < 58)))
(tl;dr I quite like doing it this way because it hides the implementation details of is.digit and creates a rudimentary form of encapsulation)
(2) A UDF - based on the example here and called as
=RegexTest(A1)
Option Explicit
Function RegexTest(s As String) As Double()
Dim regexOne As Object
Dim theNumbers As Object
Dim Number As Object
Dim result() As Double
Dim i As Integer
Set regexOne = New RegExp
' Not sure how you would extract numbers of length 6 only, so extract all numbers...
regexOne.Pattern = "\d+"
regexOne.Global = True
regexOne.IgnoreCase = True
Set theNumbers = regexOne.Execute(s)
i = 1
For Each Number In theNumbers
'...Check the length of each number here
If Len(Number) = 6 Then
ReDim Preserve result(1 To i)
result(i) = CDbl(Number)
i = i + 1
End If
Next
RegexTest = result
End Function
Note - if you wanted to preserve leading zeroes you would need to omit the Cdbl() and return the numbers as strings. Returns an error if no 6-digit numbers are found.
I have a column of Hexadecimal strings with many TRAILING zeros.
The problem i have is that the trailing Zeros from the string, needs to be removed
I have searched for a VBA formula such as Trim but my solution has not worked.
Is there a VBA formula I can use to remove all these Trailing zeros from each of the strings.
An example of the HEX string is 4153523132633403277E7F0000000000000000000000000000. I would like to have it in a format of 4153523132633403277E7F
The big issue is that the Hexadecimal strings can be of various lengths.
Formula:
You could try:
Formula in B1:
=LET(a,TEXTSPLIT(A1,,"0"),TEXTJOIN("0",0,TAKE(a,XMATCH("?*",a,2,-1))))
This would TEXTSPLIT() the input and the fact that we can then use XMATCH() to return the position of the last non-empty string with a wildcard match ?*. However, given the fact we can use arrays in our TEXTSPLIT() function, a little less verbose could be:
=TEXTBEFORE(A1,TAKE(TEXTSPLIT(A1,TEXTSPLIT(A1,"0",,1)),,-1),-1)
Or another option, though more verbose, is to use REDUCE() for what it's intended to do, which is to loop a given array:
=REDUCE(A1,SEQUENCE(LEN(A1)),LAMBDA(a,b,IF(RIGHT(a)="0",LEFT(a,LEN(a)-1),a)))
VBA:
If VBA is a must, one way of dealing with this is through the RTrim() function. Since your HEX-string should not contain spaces to begin with I think the following is a safe bet:
Sub Test()
Dim s As String: s = "4153523132633403277E7F0000000000000000000000000000"
Dim s_new As String
s_new = Replace(RTrim(Replace(s, "0", " ")), " ", "0")
Debug.Print s_new
End Sub
If you happen to have spaces anywhere else in your string, another option would be to look for trailing zero's using a regular expression:
Sub Test()
Dim s As String: s = "4153523132633403277E7F0000000000000000000000000000"
Dim s_new As String
With CreateObject("vbscript.regexp")
.Pattern = "0+$"
s_new = .Replace(s, "")
End With
Debug.Print s_new
End Sub
Both the above options should print: 4153523132633403277E7F
As far as I know, there is no function to do that for you. The way I would do it is presented in the pseudo-code below:
while last character is "0"
remove last character
end while
It is quit slow, but VBA itself is not race car either, so you will probably not notice especially if you do not need to that for many times at once.
A more beautiful solution would involve VBA being able to search for the beginning or the end of a string.
An improvement of the solution above is to parse the string backwards and count the "0" characters, and then remove them all at the same time.
I've been stuck trying different methods of doing this for a while, usually not getting anywhere productive. I've tried going down each operator and splitting the string and evaluating there, I've tried looping through each character and then checking the next character but nothing seems to work very well and efficiently.
Is there a way to do this easily? I'd want to input a string, for example, "4*4+1/1" and receive an output of 17. Or, "4^2*2" = 14
The following will compute a string.
Private Sub CompteString()
Dim equation As String = "2+3"
Dim result = New DataTable().Compute(equation, Nothing)
Debug.Print(result.ToString)
End Sub
In VBA, how do I find the first instance of a punctuation symbol, from the right hand side? For example, from "!", I should be able to get the term "Security" two times in the following string:
INDEX(Security![a range], MATCH(J2,Security![a range],0))
Something like InStrRev would be ideal but seems like it doesnt support regex expressions. Any help is greatly appreciated!
It's true that InStrRev() doesn't accept RegEx patterns, but VBA does support RegEx and there would be a way of achieving what you need with it. However, just looping through each character and looking for any punctuation mark is pretty straightforward and might be a route you prefer.
Skeleton code (with only a few punctuation marks) below:
Public Sub RunMe()
Const punc As String = "!""*()-[]{};':#~,./<>?"
Debug.Print InStrRevAny("T:E'S!T", punc)
End Sub
Private Function InStrRevAny(refText As String, chars As String) As Long
Dim i As Long, j As Long
For i = Len(refText) To 1 Step -1
For j = 1 To Len(chars)
If Mid(refText, i, 1) = Mid(chars, j, 1) Then
InStrRevAny = i
Exit Function
End If
Next
Next
End Function
I have Excel 2007. I am trying to find the largest number in a cell that contains something like the following:
[[ E:\DATA\SQL\SY0\ , 19198 ],[ E:\ , 18872 ],[ E:\DATA\SQL\ST0\ , 26211 ],[ E:\DATA\SQL\ST1\ , 26211 ],[ E:\DATA\SQL\SD0\ , 9861 ],[ E:\DATA\SQL\SD1\ , 11220 ],[ E:\DATA\SQL\SL0\ , 3377 ],[ E:\DATA\SQL\SL1\ , 1707 ],[ E:\DATA\SQL_Support\SS0\ , 14375 ],[ E:\DATA\SQL_Support\SS1\ , 30711 ]]
I am not a coder but I can get by with some basic instructions. If there is a formula that can do this, great! If the best way to do this is some sort of backend code, just let me know. Thank you for your time.
I do have the following formula that almost gets me there:
=SUMPRODUCT(MID(0&A2,LARGE(INDEX(ISNUMBER(--MID(A2,ROW(INDIRECT("1:"&LEN($A$2))),1))*ROW(INDIRECT("1:"&LEN($A$2))),0),ROW(INDIRECT("1:"&LEN($A$2))))+1,1)*10^ROW(INDIRECT("1:"&LEN($A$2)))/10)
With a cell that contains a string like above, it will work. However, with a string that contains something like:
[[ E:\DATA\SQL\SY0\ , 19198.934678 ],[ E:\ , 18872.2567 ]]
I would end up with the value of 19198934678 as the largest value.
You can use this UDF:
Function MaxInString(rng As String) As Double
Dim splt() As String
Dim i&
splt = Split(rng)
For i = LBound(splt) To UBound(splt)
If IsNumeric(splt(i)) Then
If splt(i) > MaxInString Then
MaxInString = splt(i)
End If
End If
Next i
End Function
Put this in a module attached to the workbook. NOT in the worksheet or ThisWorkbook code.
Then you can call it like any other formula:
=MaxInString(A1)
If there is always a space before and after, you can use this formula. The formula is an array formula and must be confirmed by holding down ctrl + shift while hitting enter
With your string in A1:
=MAX(IFERROR(--TRIM(MID(SUBSTITUTE(A1," ",REPT(" ",99)),IF(seq=1,1,(seq-1)*99),99)),0))
seq is a defined name that refers to:
=ROW(INDEX(Sheet1!$1:$65536,1,1):INDEX(Sheet1!$1:$65536,255,1))
If a VBA UDF is preferable, I suggest the following. The Regex will match anything that might be a number. The number is expected to be in the format of iiii.dddd The integer part and the decimal point are both optional.
Option Explicit
Function LargestNumberFromString(S As String) As Double
Dim RE As Object, MC As Object, M As Object
Dim D As Double
Set RE = CreateObject("vbscript.regexp")
With RE
.Global = True
.Pattern = "\b[0-9]*\.?[0-9]+\b"
If RE.test(S) = True Then
For Each M In MC
D = IIf(D > CDbl(M), D, CDbl(M))
Next M
End If
End With
End Function
This is going to be a rather complex answer for someone with no programming background, so be prepared to spend a lot of time covering and researching this topic if you really wish to achieve a function that finds the largest number in a string in excel.
The solution, requires the use of VBA and Regular expressions
VBA is used in excel when there is a need for more complex functionality that just can't be achieved with the use of built in spreadsheet functions.
Regular expressions are a language used to tell programs how to extract useful information from texts, in this case we can extract all the numbers in your text. with the following regular expression.
(\d+.?\d*)/g
Which roughly means: Match one or more digits with an optional period and subsequent optional digits.
The program that will interpret this will do the following: Look for digits, if you see one, then that's a match, grab all contiguous digits and add them to the match. Once you find a character that is not a digit, start looking for new matches. if at any point you find a dot, add it to the match, but just once, and keep on looking for digits. Rinse and repeat until the end of the text.
You can test it here. In this case, the regex matches 19 numbers.
http://www.regextester.com/
Once you have a collection with the 19 matches (See link to regular expressions), all you would need to do is to loop over each of the matches to find out which of the numbers is the highest:
for each number in matches
if number > highestNumber then
highestNumber = number
end if
next
And highestNumber will be the the result! In order to have this code run in a simple custom function, you can follow this microsoft tutorial ( https://support.office.com/en-us/article/Create-Custom-Functions-in-Excel-2007-2f06c10b-3622-40d6-a1b2-b6748ae8231f?ui=en-US&rs=en-US&ad=US&fromAR=1 )
Where c is your string to find max from
Dim qwe() As String
qwe = Split(c, ", ")
maxed = 0
For x = LBound(qwe) To UBound(qwe)
qwe(x) = Left(qwe(x), InStr(1, qwe(x), " ", vbBinaryCompare))
On Error Resume Next
If CLng(qwe(x)) > maxed Then maxed = CLng(qwe(x))
Next x
MsgBox maxed
The error line is there to ignore when qwe(x) cannot be converted to a LONG number.
I must say this is very specific to your string format, for a more comprehensive doodad you'd want to have the split delimiter as a variable and possibly use the "IsNumeric" function to scan the entire string.