Excel VBA Replace the nth word in a string - excel

my problem is the following:
I have two sets of strings. The "words" are separated with "+".
String 1: A25+F47+w41+r21+h65
String 2: 4+7+4+4+2
I have a textbox that identifies the word “w41” in string 1. It is the 3rd word in the string. I want to replace the 3rd word in string 2 and that would be the second “4”
What I have so far is:
I am using split function to split string 1 where there is a “+”:
Result=Split(String1, "+")
Then I use the UBound to find the position of w41 and the result is 3.
FindWordPosition = UBound(Result()) + 1
Now I want to split string 2 in the same way. But then I want to change the 3rd word in string 2 from “4” to “3” and then put it together again. The result would be:
String 2: 4+7+3+4+2
but I cannot figure out how to do it :(

One way is to use an ArrayList.
Not sure what you want to replace the matched item with. In the code below, it is being replaced with the sequence number, which matches what you describe, but may not be what you really want.
Option Explicit
Sub due()
Const str1 As String = "A25+F47+w41+r21+h65"
Const str2 As String = "4+7+4+4+2"
Const strMatch As String = "w41"
Dim AL As Object
Dim v, w, I As Long
Set AL = CreateObject("System.Collections.ArrayList")
'put str2 into arrayList
v = Split(str2, "+")
For Each w In v
AL.Add w
Next w
'Check str1 against matchStr to get positions and act on the item in AL at that position
v = Split(str1, "+")
For I = 0 To UBound(v)
'Note that arrayList index and "Split" array are zero-based
If strMatch = v(I) Then
AL.removeat I 'remove item in the same position as the position of the matched item
AL.Insert I, I + 1 'Insert new item at that same position. Could be anything. I chose I+1 to match what you wrote in your question.
End If
Next I
Debug.Print Join(AL.toarray, "+")
End Sub
=> 4+7+3+4+2

Replace With Index
This example should get you on your feet.
The Code
Option Explicit
' Results
' For w41:
' A25+F47+w41+r21+h65
' 4+7+3+4+1
' For h65:
' A25+F47+w41+r21+h65
' 4+7+4+4+5
Sub replaceWithIndex()
Const Criteria As String = "w41"
Const str1 As String = "A25+F47+w41+r21+h65"
Const str2 As String = "4+7+4+4+1"
Const Delimiter As String = "+"
Dim Split1() As String: Split1 = Split(str1, Delimiter)
Dim Split2() As String: Split2 = Split(str2, Delimiter)
' Note that an array obtained with 'Split' is always zero-based, while
' the result of 'Application.Match' is always one-based (hence '- 1').
Dim cMatch As Variant: cMatch = Application.Match(Criteria, Split1, 0)
If IsNumeric(cMatch) Then
Split2(cMatch - 1) = cMatch
Debug.Print "Source"
Debug.Print str1
Debug.Print str2
Debug.Print "Result"
Debug.Print Join(Split1, Delimiter)
Debug.Print Join(Split2, Delimiter)
End If
End Sub

You can simply loop the array and exit if found:
Public Sub BuildPositions()
Const Criteria As String = "w41"
Const String1 As String = "A25+F47+w41+r21+h65"
Const String2 As String = "4+7+4+4+2"
Const Delimiter As String = "+"
Dim Results() As String
Dim Positions() As String
Dim Index As Integer
Results = Split(String1, Delimiter)
Positions = Split(String2, Delimiter)
For Index = LBound(Results) To UBound(Results)
If Results(Index) = Criteria Then
Exit For
End If
Next
If Index <= UBound(Results) Then
' Result was located.
Positions(Index) = 1 + Index
End If
Debug.Print "Results:", String1
Debug.Print "Positions1:", String2
Debug.Print "Positions2:", Join(Positions, Delimiter)
End Sub
Output:
Results: A25+F47+w41+r21+h65
Positions1: 4+7+4+4+2
Positions2: 4+7+3+4+2

Related

VBA printing a substring from a string

I would like to print each substrings in between the "..." from this string: "...covid...is...very...scary" in consecutive cells in a column in excel.
this is my code in VBA.
Sub copyd()
findandcopy("...covid...is...very...scary") 'not sure how to print in consecutive cells of a column
End Sub
Function findandcopy(brokenstr As String) As String
Dim first, second As Integer
Dim strtarget as string
strtarget = "..."
Do until second =0. 'second=0 so that loop ends when there is no more "..." found
first = InStr(brokenstr, strtarget)
second = InStr(first + 3, brokenstr, strtarget)
findandcopy = Mid(purpose, first +3, second - first -3) 'referred to https://stackoverflow.com/questions/2543225/how-to-get-a-particular-part-of-a-string#_=_
first = second 'so that loop can find next "..."
Loop
End Function
can anyone please advise? thank you for your help :)
Try this code:
Option Explicit
Sub copyd()
Dim arr As Variant
' get splitted text into horizontal array arr()
arr = Split("...covid...is...very...scary", "...")
If UBound(arr) > 0 Then ' if there is something in the array, display it on the sheet
' put onto sheet values from transposed array arr()
ThisWorkbook.Worksheets(1).Range("A1"). _
Resize(UBound(arr) + 1, 1).Value = _
WorksheetFunction.Transpose(arr)
End If
End Sub
Ahh, why not just split the string by "..."?
Like:
Function findandcopy(brokenstr As String, targetStr as string)
dim substr()
if instr(1, brokenstr, targetStr, vbTextCompare) > 0 then
'brokenstr has at least one instance of targetStr in it
brokenstr2 = split(brokenstr,targetStr)
if brokenstr2(0) = "" then
redim substr(ubound(brokenstr2)-1)
iStart = 1
else
redim substr(ubound(brokenstr2))
iStart = 0
end if
for i = iStart to ubound(brokenstr2)
substr(i-iStart) = brokenstr2(i)
next i
else
'No instances of targetStr in brokenstr
redim substr(0)
substr(0) = brokenstr
end if
findandcopy = substr
end function
Which will return an array of strings which are the bits between targetStr. Then you can do with it as you please within the parent sub.
If you start doing comparisons with the results and find issues - you can remove whitespace by modifying above as:
substr(i) = trim(brokenstr2(i))
and your calling code:
Sub main()
Dim covid as string
Dim remove as string
covid = "...covid...is....very...scary"
'covid = "really...covid...is...very...scary" 'For testing
remove = "..."
rtn = findandcopy(covid, remove)
end sub

Extract A String Between Two Characters In Excel

theStr = "KT150"
Characters count is always 5 in total. I want to make sure that there is 3 numbers in theStr. How would I achieve this in Excel VBA?
You do not need VBA to get the number of digits in a string, but here is one way to count them:
Public Function KountNumbers(r As Range) As Long
Dim i As Long, t As String
t = r.Text
For i = 1 To Len(t)
If Mid(t, i, 1) Like "[0-9]" Then KountNumbers = KountNumbers + 1
Next i
End Function
for example:
Without VBA try this:
=SUMPRODUCT(LEN(A1)-LEN(SUBSTITUTE(A1,{0,1,2,3,4,5,6,7,8,9},"")))
to get the number of numeric digits.
Your question is a little lacking in detail, but how about:
Sub test()
Debug.Print containsXnumbers("KT150", 3)
End Sub
Function containsXnumbers(sInput As String, xNumbers As Long) As Boolean
Dim x As Long
Dim numCount As Long
For x = 1 To Len(sInput)
If IsNumeric(Mid(sInput, x, 1)) Then numCount = numCount + 1
Next x
If numCount = xNumbers Then containsXnumbers = True
End Function
This should help:
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
Example:
Dim myStr as String
myStr = onlyDigits ("3d1fgd4g1dg5d9gdg")
MsgBox (myStr)
Will return (in a message box):
314159
*Code is exact copy of this SO answer
try with the below formula
Assume that your data are in A1. Apply the below formula in B1
=IF(AND(LEN(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"1",""),"2",""),"3",""),"4",""),"5",""),"6",""),"7",""),"8",""),"9",""),"0",""))=2,LEN(A1)=5),"3 character numerals","No 3 numerals found")

Split string and delimiters into an array

I have the following string:
top,fen,test,delay,test
I want to convert it into an array in the following way:
{top}{,}{fen}{,}{delay}{,}{test}
If you actually need the commas as part of the array, then probably the simplest approach is to do a Replace statement, replacing each comma with a comma surrounded by some other character(s) you can use as a delimiter. Whatever character you opt to use should be unique enough that it is unlikely to appear in the rest of your word list. I will use an underscore, here, but you could use any other special character.
Sub test()
Dim wordlist As String
Dim arrayofWords
Dim i
wordlist = "top,fen,test,delay,test"
wordlist = Replace(wordlist, ",", "_,_")
arrayofWords = Split(wordlist, "_")
'Enclose each word in curly brackets
' omit if this part is not needed
For i = LBound(arrayofWords) To UBound(arrayofWords)
arrayofWords(i) = "{" & arrayofWords(i) & "}"
Next
End Sub
You could use some funky double-byte character since these would rarely if ever be encountered in your word list, like so.
Sub test()
Const oldDelimiter As String = ","
Dim splitter As String
Dim newDelimiter As String
Dim wordlist As String
Dim arrayofWords
Dim i As Long
'Create our new delimiter by concatenating a new string with the comma:
splitter = ChrW(&H25B2)
newDelimiter = splitter & oldDelimiter & splitter
'Define our word list:
wordlist = "top,fen,test,delay,test"
'Replace the comma with the new delimiter, defined above:
wordlist = Replace(wordlist, oldDelimiter, newDelimiter)
'Use SPLIT function to convert the string to an array
arrayofWords = Split(wordlist, splitter)
'Iterate the array and add curly brackets to each element
'Omit if this part is not needed
For i = LBound(arrayofWords) To UBound(arrayofWords)
arrayofWords(i) = "{" & arrayofWords(i) & "}"
Next
End Sub
Here are results from the second method:
Try something like this :
WordsList = Split("top,fen,test,delay,test", ",")
Result = ""
Count = UBound(WordsList)
For i = 0 To Count
Result = Result & "{" & WordsList(i) & "}"
if i < Count then Result = Result & "{,}"
Next i
In an array will look like this :
WordsList = Split("top,fen,test,delay,test", ",")
Dim Result()
Count = (UBound(WordsList)*2) - 1
Redim Result(Count)
j = 0
For i = 0 To UBound(WordsList)
Result(j) = WordsList(i)
j = j + 1
if j < Count then Result(j) = ","
j = j + 1
Next i
Split : http://msdn.microsoft.com/en-us/library/6x627e5f%28v=vs.90%29.aspx
UBound : http://msdn.microsoft.com/en-us/library/95b8f22f%28v=vs.90%29.aspx
Redim : http://msdn.microsoft.com/en-us/library/w8k3cys2.aspx
Here's a really short solution:
Function StringToCurlyArray(s As String) As String()
StringToCurlyArray = Split("{" & Replace(s, ",", "}|{,}|{") & "}", "|")
End Function
Pass your comma-delimited string into that and you'll get an array of curly-braced strings back out, including commas.

Split string into array of characters?

How is it possible to split a VBA string into an array of characters?
I tried Split(my_string, "") but this didn't work.
Safest & simplest is to just loop;
Dim buff() As String
ReDim buff(Len(my_string) - 1)
For i = 1 To Len(my_string)
buff(i - 1) = Mid$(my_string, i, 1)
Next
If your guaranteed to use ansi characters only you can;
Dim buff() As String
buff = Split(StrConv(my_string, vbUnicode), Chr$(0))
ReDim Preserve buff(UBound(buff) - 1)
You can just assign the string to a byte array (the reverse is also possible). The result is 2 numbers for each character, so Xmas converts to a byte array containing {88,0,109,0,97,0,115,0} or you can use StrConv
Dim bytes() as Byte
bytes = StrConv("Xmas", vbFromUnicode)
which will give you {88,109,97,115} but in that case you cannot assign the byte array back to a string. You can convert the numbers in the byte array back to characters using the Chr() function
Here's another way to do it in VBA.
Function ConvertToArray(ByVal value As String)
value = StrConv(value, vbUnicode)
ConvertToArray = Split(Left(value, Len(value) - 1), vbNullChar)
End Function
Sub example()
Dim originalString As String
originalString = "hi there"
Dim myArray() As String
myArray = ConvertToArray(originalString)
End Sub
According to this code golfing solution by Gaffi, the following works:
a = Split(StrConv(s, 64), Chr(0))
the problem is that there is no built in method (or at least none of us could find one) to do this in vb. However, there is one to split a string on the spaces, so I just rebuild the string and added in spaces....
Private Function characterArray(ByVal my_string As String) As String()
'create a temporary string to store a new string of the same characters with spaces
Dim tempString As String = ""
'cycle through the characters and rebuild my_string as a string with spaces
'and assign the result to tempString.
For Each c In my_string
tempString &= c & " "
Next
'return return tempString as a character array.
Return tempString.Split()
End Function
To split a string into an array of sub-strings of any desired length:
Function charSplitMulti(s As Variant, splitLen As Long) As Variant
Dim padding As Long: padding = 0
Dim l As Long: l = 0
Dim v As Variant
'Pad the string so it divides evenly by
' the length of the desired sub-strings
Do While Len(s) Mod splitLen > 0
s = s & "x"
padding = padding + 1
Loop
'Create an array with sufficient
' elements to hold all the sub-strings
Do Until Len(v) = (Len(s) / splitLen) - 1
v = v & ","
Loop
v = Split(v, ",")
'Populate the array by repeatedly
' adding in the first [splitLen]
' characters of the string, then
' removing them from the string
Do While Not s Like ""
v(l) = Mid(s, 1, splitLen)
s = Right(s, Len(s) - splitLen)
l = l + 1
Loop
'Remove any padding characters added at step one
v(UBound(v)) = Left(v(UBound(v)), Len(v(UBound(v))) - padding)
'Output the array
charSplitMulti = v
End Function
You can pass the string into it either as a string:
Sub test_charSplitMulti_stringInput()
Dim s As String: s = "123456789abc"
Dim subStrLen As Long: subStrLen = 4
Dim myArray As Variant
myArray = charSplitMulti(s, subStrLen)
For i = 0 To UBound(myArray)
MsgBox myArray(i)
Next
End Sub
…or already declard as a variant:
Sub test_charSplitMulti_variantInput()
Dim s As Variant: s = "123456789abc"
Dim subStrLen As Long: subStrLen = 5
s = charSplitMulti(s, subStrLen)
For i = 0 To UBound(s)
MsgBox s(i)
Next
End Sub
If the length of the desired sub-string doesn't divide equally into the length of the string, the uppermost element of the array will be shorter. (It'll be equal to strLength Mod subStrLength. Which is probably obvious.)
I found that most-often I use it to split a string into single characters, so I added another function, so I can be lazy and not have to pass two variables in that case:
Function charSplit(s As Variant) As Variant
charSplit = charSplitMulti(s, 1)
End Function
Sub test_charSplit()
Dim s As String: s = "123456789abc"
Dim myArray As Variant
myArray = charSplit(s)
For i = 0 To UBound(myArray)
MsgBox myArray(i)
Next
End Sub
Try this minicode From Rara:
Function charSplitMulti(TheString As Variant, SplitLen As Long) As Variant
'Defining a temporary array.
Dim TmpArray() As String
'Checking if the SplitLen is not less than one. if so the function returns the whole string without any changing.
SplitLen = IIf(SplitLen >= 1, SplitLen, Len(TheString))
'Redefining the temporary array as needed.
ReDim TmpArray(Len(TheString) \ SplitLen + IIf(Len(TheString) Mod SplitLen <> 0, 1, 0))
'Splitting the input string.
For i = 1 To UBound(TmpArray)
TmpArray(i) = Mid(TheString, (i - 1) * SplitLen + 1, SplitLen)
Next
'Outputing the result.
charSplitMulti = TmpArray
End Function

Excel macro to read text file word by word and write every word to a new cell in the same column

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

Resources