With excel macro (VBA), I need to generate hash total for a series of strings. My current function cant output the correct result.
How to derive the hash total is as such:
Subtract the first 11 characters of originating account from the
first 11 characters of each receiving account.
If the account number is less than 11 characters, pad 0 on the right.
If the
account number has an alphabet, convert the alphabet to 0.
Derive the value for each receiving account. Take the absolute value, that
is, ignore the negative sign.
Add the absolute values
Take the first 11 character of the result. If the result is less
than 11 characters, pad with 0 on the left.
This is what I have now:
Function cleanString(text As String) As String
Dim output As String
Dim i As Integer
Dim c 'since char type does not exist in vba, we have to use variant type.
For i = 1 To Len(text)
'With Sheet2
MsgBox (i)
c = Mid(text, i, 1) 'Select the character at the i position
If (c >= "a" And c <= "z") Or (c >= "A" And c <= "Z") Then
output = output & "0" 'add the character to your output.
Else
output = output & c 'add the replacement character (space) to your output
End If
'End With
Next
cleanString = output
End Function
Function generateHash(LastRows As Long) As Double
Dim output As Double
'Dim c 'since char type does not exist in vba, we have to use variant type.
Dim Orig As String
Dim AccNo As String
Dim temp As Long
Orig = Left(Range("B3") & String(34, " "), 34)
For LastRows = 9 To LastRows
With Sheet2
AccNo = Left(.Cells(LastRows, 5) & String(11, " "), 11)
AccNo = cleanString(AccNo)
temp = Abs(AccNo - Orig)
output = output + temp
'MsgBox (output)
End With
Next
generateHash = output
End Function
These are the 26 sample strings, which should produce the hash total of "31341437052"
0039002572
0039002580
0030015769
0030016412
0259001090
0259001111
0039002637
0100703387
0100703395
0100703425
0100703433
0100703441
0100703450
0100703468
0100703476
0100703484
0011227958
0011228946
951382892
951700711
301402570
402705981
0030001620
0036001622
111111111
222222222
ok. so i figure out it was just some parameters that i was missing.
This convert any alphabet in the string to "0"
Function cleanString(text As String) As String
Dim output As String
Dim i As Integer
Dim c 'since char type does not exist in vba, we have to use variant type.
For i = 1 To Len(text)
'With Sheet2
'MsgBox (i)
c = Mid(text, i, 1) 'Select the character at the i position
If (c >= "a" And c <= "z") Or (c >= "A" And c <= "Z") Then
output = output & "0" 'add the character to your output.
Else
output = output & c 'add the replacement character (space) to your output
End If
'End With
Next
cleanString = output
'MsgBox (cleanString)
End Function
This start the hash function
Function generateHash(LastRows As Long) As Double
Dim output As Double
'Dim c 'since char type does not exist in vba, we have to use variant type.
Dim Orig As String
Dim AccNo As String
Dim temp As String
Dim lCounter As Long
Dim lLastRow As Long
'Find the last row that contains data
With Sheet2
lLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
'Take the original string and making sure there are only 11 characters
Orig = Left(Range("B3") & "00000000000", 11)
'Starts from row 9
For lCounter = 9 To LastRows
With Sheet2
'Ensuring only 11 characters
AccNo = Left(.Cells(lCounter, 5) & "00000000000", 11)
'Clean the string of any alphabet
AccNo = cleanString(AccNo)
'Take the absolute diff of 2nd and 1st string
temp = Abs(AccNo - Orig)
output = output + temp
'MsgBox (output)
End With
Next
generateHash = output
End Function
Related
I'm trying to turn general data written as fractions like 3/4" or 13 7/32" into 3 place decimal numbers such as 0.750 or 13.219.
I have a working table replacement that handles 0 to 1" fractions. It can't handle the mixed numbers like 13 7/32". It leaves me with 13 0.219 which is why I need to replace " 0." with "." to join the 13 and 219 together with a decimal.
We do this data conversion in multiple steps and hand type because Excel tries converting some fractions like 3/4" into a date.
Original data
Resulting data
Sub FractionConvertMTO()
'this section works
For i = 6 To 70
Worksheets("BOM").Range("F6:H48").Select
Selection.Replace what:=Cells(i, 21).Value, Replacement:=Cells(i, 22).Value, _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
Next
'this section doesn't work
For i = 6 To 70
Worksheets("BOM").Range("F6:H48").Select
str1 = " "
str1 = Trim(Replace(str1, " ", "+"))
Next
'this section changes the format.
For i = 66 To 130
Range("F6:H48").NumberFormat = "0.000"
Next
'this section is supposed to add an = sign in front of the cell contents but doesn't work.
Dim Cell As Range
For Each Cell In Range("F6:H48")
Cell.Value = "=" & Cell.Value
Next Cell
'this section works to highlight the first cell
Worksheets("BOM").Cells(1, 1).Select
End Sub
I dug up the following method from my library of useful functions. It converts numbers represented as a fractional string to the numeric equivalent. Simply loop through the cells needing conversion and call this method:
Public Function FractionToNumber(ByVal Value As String, Optional ByVal Digits As Long = 0) As Double
Dim P As Integer
Dim N As Double
Dim Num As Double
Dim Den As Double
Value = Trim$(Value)
P = InStr(Value, "/")
If P = 0 Then
N = Val(Value)
Else
Den = Val(Mid$(Value, P + 1))
Value = Trim$(Left$(Value, P - 1))
P = InStr(Value, " ")
If P = 0 Then
Num = Val(Value)
Else
Num = Val(Mid$(Value, P + 1))
N = Val(Left$(Value, P - 1))
End If
End If
If Den <> 0 Then N = N + Num / Den
FractionToNumber = Round(N, Digits)
End Function
You may also code something like the following:
Sub FractionConvertMTO()
Dim rng As Range
Dim Arr As Variant
Arr = Worksheets("MTO").Range("F6:H48")
For Row = 1 To UBound(Arr, 1)
For col = 1 To UBound(Arr, 2)
str1 = Arr(Row, col)
pos1 = InStr(str1, " ")
pos2 = InStr(str1, "/")
If pos2 = 0 Then
N = val(str1)
Num = 0: Den = 1
Else
If pos1 And pos1 < pos2 Then
N = val(Left$(str1, pos1 - 1))
Num = val(Mid$(str1, pos1 + 1))
Else
N = 0
Num = val(Left$(str1, pos2 - 1))
End If
Den = val(Mid$(str1, pos2 + 1))
End If
Arr(Row, col) = N + Num / Den
Next col
Next Row
Worksheets("MTO").Range("F6", "H48") = Arr
End Sub
If you dispose of the newer dynamic array features (vers. 2019+,MS365) you might write the results in one go to the entire original range (target range) as follows (overwriting the existing range; otherwise define a given offset to identify another target range: rng.Offset(,n)=..).
Tip: make a backup copy before testing (as it overwrites rng)!
Note that this example assumes the " character (asc value of 34).
A) First try via tabular VALUE() formula evaluation
Caveat: converting blanks by VALUE() would be written as #VALUE! results, which would need a further loop. To avoid this you can prefix a zero to the formulae myFormula = "=VALUE(SUBSTITUTE(" & """0""&" & rng.Address & ","""""""",""""))" so that results would be displayed as zero.
Sub ChangeToFractionValues()
'1) define original range to be replaced
Dim rng As Range
Set rng = ThisWorkbook.Worksheets("BOM").Range("F6:H48")
'2) define tabular formula
Dim myFormula As String
'myFormula = "=VALUE(SUBSTITUTE(" & rng.Address & ","""""""",""""))"
'Alternative to avoid #VALUE! displays for blanks:
myFormula = "=VALUE(SUBSTITUTE(" & """0""&" & rng.Address & ","""""""",""""))"
'Debug.Print myFormula
'3) overwrite original range (otherwise code an offset rng.Offset(,n).Value = ...
rng.Value2 = rng.Parent.Evaluate(myFormula)
End Sub
Conclusion due to comment:
Though fast, this approach has a big disadvantage: Excel interpretes date-like numbers as such, transforms them internally to dates by returning the numeric part here, so a cell input of 3/4" would return the corresponding date value of the current year for March 4th.
B) Reworked code based on direct cell evaluations in a loop //Edit
Similar to the above processing this approach is also based on evaluation, but collects all formulae as strings in a variant datafield array v, which allows to manipulate and evaluate each cell input individually:
Sub ChangeToFractionValues()
'1) define original range to be replaced
Dim rng As Range
Set rng = ThisWorkbook.Worksheets("BOM").Range("F6:H48")
'2) assign formula strings to variant 1-based 2-dim data field array
Dim v As Variant
v = rng.Formula2
'3) evaluate results in a loop
Dim i As Long, j As Long
For i = 1 To UBound(v)
For j = 1 To UBound(v, 2)
v(i, j) = Evaluate("0" & Replace(v(i, j), Chr(34), ""))
Next j
Next i
'4) overwrite original range (otherwise code an offset rng.Offset(,n).Value = ...
rng.Value = v
End Sub
str1 = trim(Replace(str1, "0.", "."))
I've the following Excel data:
A B C
+ ------------ ------------- -----------------
1 | WORD WORD MIX MATCH TEXT RESULT
2 | somewordsome emsomordsowe ...
3 | anotherword somethingelse ...
4 | ... ... ...
I'd like to:
Firstly, get an array, say ArrayOfGroups, by splitting the string in the A2 cell in unique groups of 2 to 12 adjacent chars (note: 2 is the minimum number of chars to form a group; 12 is the total number of the word's chars) i.e. the groups of 2 chars would be so, om, me, ew, wo, or, rd, ds (note: the last so, om and me groups are excluded because they are repeated); the groups of 3 chars would be som, ome, mew, ewo, wor, ord, rds, dso (last som and ome excluded); the groups of 4 chars would be some, omew, mewo, ewor, word, ords, rdso, dsom; ... and so on until the full string somewordsome.
Then, iterate the above-mentioned ArrayOfGroups to check if each of its element is a substring of the B2 cell and return a new array, say ArrayOfMatches, containing all the elements (the characters "group names") that are substrings of B2 and the number of occurrences found in B2.
Finally, output in the C2 cell a sentence built using the ArrayOfMatches data that says something like this:
2 matches for so, 1 match for som and rd
Probably there are other and better approaches to compute the above sentence that is the final result wanted. Maybe I need to use a User Defined Function... but I never made it.
Is there someone that could give help?
May try something like this
Code edited to avoid counting for same substring found multiple times.
Sub test2()
Dim Xstr As String, Ystr As String
Xstr = "somewordsome"
Ystr = "emsomordsowe"
MsgBox Xmatch2(Xstr, Ystr)
End Sub
Function Xmatch2(Xstr As String, Ystr As String) As String
Dim XSubStr As String, YSubStr As String
Dim xLn As Integer, yLn As Integer
Dim XArr As Variant, LnSubStr As Integer
Dim Rslt As String, Cnt As Integer
Dim Xrr() As Variant, Xcnt As Integer, Chk As Boolean
Rslt = "'"
xLn = Len(Xstr)
yLn = Len(Ystr)
For LnSubStr = 2 To xLn 'length of substring
Xcnt = 0
ReDim XArr(1 To 1)
For Y = 1 To xLn
XSubStr = ""
Xcnt = Xcnt + 1
ReDim Preserve XArr(1 To Xcnt)
If Y + LnSubStr - 1 <= xLn Then XSubStr = Mid(Xstr, Y, LnSubStr)
XArr(Xcnt) = XSubStr
Chk = False
For i = 1 To Xcnt - 1
If XArr(i) = XSubStr Then
Chk = True
Exit For
End If
Next
If XSubStr <> "" And Chk = False Then
Cnt = 0
ReDim Preserve XArr(1 To Xcnt)
For Z = 1 To yLn
YSubStr = ""
If Z + LnSubStr - 1 <= yLn Then YSubStr = Mid(Ystr, Z, LnSubStr)
If YSubStr = XSubStr Then Cnt = Cnt + 1
Next
If Cnt > 0 Then Rslt = Rslt & Cnt & " Matches for " & XSubStr & ","
End If
Next
Next
Debug.Print Rslt
Xmatch2 = Rslt
End Function
I have a macro that goes through a list of text, extracts the dollar amounts, increase them by 12%, and replaces the text with the updated dollar amounts.
This what a couple rows of data looks like:
This is the result after I run the macro:
I would need the 72.8 to be 72.80 tho, for example.
Sometimes the result would just have 1 decimal place and sometimes it would have 3. The Round function works fine for me with truncating the result down to 2 decimal places, but doesn't help adding a 0 to keep the number at two decimal places.
I need a way to have fill the second decimal place with a 0 if the result only has 1 decimal place.
This is the macro:
Function onlyDigits(s As String) As String
' Variables needed (remember to use "option explicit"). '
Dim retval As String ' This is the return string. '
Dim i As Integer ' Counter for character position. '
' Initialise return string to empty '
retval = ""
' For every character in input string, copy digits to '
' return string. '
For i = 1 To Len(s)
If Mid(s, i, 1) >= "0" And Mid(s, i, 1) <= "9" Then
retval = retval + Mid(s, i, 1)
End If
Next
' Then return the return string. '
onlyDigits = retval
End Function
Sub ChangeDollarAmount()
Dim qtyspec As String
Dim previousDollarIndex As Integer
Dim dollarSignCount As Integer
Dim dollarString As String
Dim originalDollarAmount As String
Dim changedDollarAmount As Double
Dim isANumber As Boolean
previousDollarIndex = 1
' row count
lastrow = ActiveSheet.Range("A1").CurrentRegion.Rows.Count
For Each cell In Range("K2:K" & lastrow)
Debug.Print cell.Formula
previousDollarIndex = 1
qtyspec = cell.Formula
dollarSignCount = (Len(cell.Formula) - Len(Replace(cell.Formula, "$", ""))) / Len("$")
' loop through dollar amounts in text
For i = 1 To dollarSignCount
isANumber = False
previousDollarIndex = InStr(previousDollarIndex + 1, cell.Formula, "$")
originalDollarAmount = Mid(cell.Formula, previousDollarIndex, 8)
Do While isANumber = False
If Not IsNumeric(Right(originalDollarAmount, 1)) Then
originalDollarAmount = Left(originalDollarAmount, Len(originalDollarAmount) - 1)
Else
isANumber = True
End If
Loop
' extract only digits from dollar amount ($345.23 -> 34523)
dollarAmount = onlyDigits(originalDollarAmount)
' add decimal point and increase dollar amount by 12% (34523 -> 345.23 -> 386.66)
changedDollarAmount = Round(CDbl(dollarAmount) * 1.12 * 0.01, 2)
' update the dollar amount in the text
cell.Formula = Replace(cell.Formula, originalDollarAmount, "$" + CStr(changedDollarAmount))
Next i
Next cell
End Sub
changedDollarAmount = CDbl(dollarAmount) * 1.12 * 0.01
cell.Formula = Replace(cell.Formula, originalDollarAmount, Format$(changedDollarAmount, "$0.00"))
For Example,
I'd like a String such as, "This is a Bunch of Words in a sequence of 13 possible 1 words from a Dictionary or BookZZ or Libgen.io 1876" to give me a result of 19 (because "13", "1876" and "1" are numbers and should not be counted).
I created Two Functions which I'm trying to use within this Function I'm asking about:
The first one is the following:
' NthWord prints out the Nth Word of a String of Text in an Excel Cell such
' as A1 or B19.
Function NthWord(ActiveCell As String, N As Integer)
Dim X As String
X = ActiveCell
X = Trim(Mid(Replace(ActiveCell, " ", Application.WorksheetFunction.Rept("
", Len(ActiveCell))), (N - 1) * Len(ActiveCell) + 1, Len(ActiveCell)))
NthWord = X
' In the Excel SpreadSheet:
' Trim (Mid(Substitute(A1, " ", Rept(" ", Len(A1))), (N - 1) * Len(A1)
' + 1, Len(A1)))
End Function
The second one is the following:
'NumberOfWords returns the number of words in a String
Function NumberOfWords(ActiveCell As String)
Dim X As String
X = ActiveCell
Dim i As Integer
i = 0
If Len(Trim(X)) = 0 Then
i = 0
Else:
i = Len(Trim(X)) - Len(Replace(X, " ", "")) + 1
End If
NumberOfWords = i
' In the Excel SpreadSheet
' IF(LEN(TRIM(A1))=0,0,LEN(TRIM(A1))-LEN(SUBSTITUTE(A1," ",""))+1)
End Function
My Attempt at printing the NumberOfNonNumberWords
Function NumberOfNonNumberWords(ActiveCell As String)
Dim X As String
X = ActiveCell
Dim count As Integer
count = 0
Dim i As Integer
If NumberOfWords(X) > 0 Then
For i = 1 To NumberOfWords(X)
If Not (IsNumeric(NthWord(X, i).Value)) Then
count = count + 1
End If
Next i
End If
NumberOfNonNumberWords = count
End Function
However, when I apply this function in the Excel Worksheet, I get an output of
#VALUE!
and I'm not sure why. How do I fix this?
Split the whole string then count non-numeric elements.
function abcWords(str as string) as long
dim i as long, arr as variant
arr = split(str, chr(32))
for i=lbound(arr) to ubound(arr)
abcWords = abcWords - int(not isnumeric(arr(i)))
next i
end function
You could just use SPLIT() to split the text on a space delimiter, then count the non-numeric words:
Function num_words(ByVal text As String)
Dim txt_split
txt_split = Split(text, " ")
Dim total_words As Long
total_words = 0
Dim i As Long
For i = LBound(txt_split) To UBound(txt_split)
If Not IsNumeric(txt_split(i)) Then
total_words = total_words + 1
End If
Next i
num_words = total_words
End Function
I have a huge txt file with email ids delimited by , (space), or ;, or a combination of these.
I would like to separate these email ids and write them into new cells in just one column, row after row in the excel file.
Excel's delimited import is unable to show all ids as there are only 256 columns. And the number of words I have run into thousands. And is best suited to be inserted row by row into a new cell of the same column.
input text file looks like:
abc#abc.com; xyx#xyc.com, ext#124.de, abcd#cycd.com
required output to excel file:
abc#abc.com
xyx#xyc.com
ext#124.de
abcd#cycd.com
Reference: http://www.experts-exchange.com/Software/Office_Productivity/Office_Suites/MS_Office/A_1480-How-to-Split-a-String-with-Multiple-Delimiters-in-VBA.html
Your question contains a few part
1.Read txt file into a string (Excel has string limit) I have tried receiving an Error message "Out of String Space" , so I hope your "Huge" file isn't > 1G or something
2.Split them by mutli-delimiters
3.Output email per row
Sub Testing()
Dim fname As String
Dim sVal As String
Dim count As Long
Dim ws As Worksheet
Set ws = Worksheets("Sheet2") 'Replace Sheet1 with the output sheet name you want
fname = "H:\My Documents\a.txt" 'Replace the path with your txt file path
sVal = OpenTextFileToString2(fname)
Dim tmp As Variant
tmp = SplitMultiDelims(sVal, ",; ", True) ' Place the 2nd argument with the list of delimiter you need to use
count = 0
For i = LBound(tmp, 1) To UBound(tmp, 1)
count = count + 1
ws.Cells(count, 1) = tmp(i) 'output on the first column
Next i
End Sub
Function OpenTextFileToString2(ByVal strFile As String) As String
' RB Smissaert - Author
Dim hFile As Long
hFile = FreeFile
Open strFile For Input As #hFile
OpenTextFileToString2 = Input$(LOF(hFile), hFile)
Close #hFile
End Function
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' SplitMultiDelims by alainbryden
' This function splits Text into an array of substrings, each substring
' delimited by any character in DelimChars. Only a single character
' may be a delimiter between two substrings, but DelimChars may
' contain any number of delimiter characters. It returns a single element
' array containing all of text if DelimChars is empty, or a 1 or greater
' element array if the Text is successfully split into substrings.
' If IgnoreConsecutiveDelimiters is true, empty array elements will not occur.
' If Limit greater than 0, the function will only split Text into 'Limit'
' array elements or less. The last element will contain the rest of Text.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function SplitMultiDelims(ByRef Text As String, ByRef DelimChars As String, _
Optional ByVal IgnoreConsecutiveDelimiters As Boolean = False, _
Optional ByVal Limit As Long = -1) As String()
Dim ElemStart As Long, N As Long, M As Long, Elements As Long
Dim lDelims As Long, lText As Long
Dim Arr() As String
lText = Len(Text)
lDelims = Len(DelimChars)
If lDelims = 0 Or lText = 0 Or Limit = 1 Then
ReDim Arr(0 To 0)
Arr(0) = Text
SplitMultiDelims = Arr
Exit Function
End If
ReDim Arr(0 To IIf(Limit = -1, lText - 1, Limit))
Elements = 0: ElemStart = 1
For N = 1 To lText
If InStr(DelimChars, Mid(Text, N, 1)) Then
Arr(Elements) = Mid(Text, ElemStart, N - ElemStart)
If IgnoreConsecutiveDelimiters Then
If Len(Arr(Elements)) > 0 Then Elements = Elements + 1
Else
Elements = Elements + 1
End If
ElemStart = N + 1
If Elements + 1 = Limit Then Exit For
End If
Next N
'Get the last token terminated by the end of the string into the array
If ElemStart <= lText Then Arr(Elements) = Mid(Text, ElemStart)
'Since the end of string counts as the terminating delimiter, if the last character
'was also a delimiter, we treat the two as consecutive, and so ignore the last elemnent
If IgnoreConsecutiveDelimiters Then If Len(Arr(Elements)) = 0 Then Elements = Elements - 1
ReDim Preserve Arr(0 To Elements) 'Chop off unused array elements
SplitMultiDelims = Arr
End Function
Another way:
Sub importText()
Const theFile As String = "Your File Path"
Dim rng
Open theFile For Input As #1
rng = Application.Transpose(Filter(Split(Replace(Replace(Input(LOF(1), 1), " ", ""), ",", ";"), ";"), "#"))
Close
Sheets(1).Cells(1, 1).Resize(UBound(rng)).Value = rng
End Sub
EDIT
As per the suggestion, I've update the above to deal with consecutive mixed delimiters (,;) so the above will allow for something like:
abc#abc.com; xyx#xyc.com, ext#124.de, abcd#cycd.com;,;,; abc#abc.com;; xyx#xyc.com,,; ext#124.de, abcd#cycd.com