using VBA, how to remove the addidtional repeated characters at last - vba

I have multiple rows, I need to join with "##" characters at end of every cell value,
I am able add this characters but at the end it is printing extra characters(##)
My excel file: From this excel file, I need to join the values by ## for each cell and feed into notepad
Excel File for Input
My output should be:(Actual and Expected)
Actual and Expected Output
Here Is my code:
sub join()
dim LRow as long
dim LCol as long
Dim str1 as string
Dim str2 as string
Dim ws1 As Worksheet
Set ws1 = ActiveWorkbook.Worksheets(1)
plik = ThisWorkbook.Path & "\" & "BL2ASIS" & ws1.Name & ".txt"
Open plik For Output As 2
With ws1
LRow = .Cells(.Rows.Count, 1).End(xlUp).Row
LCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
LCol = LCol - 2
slast = vbNullString
str2 = Join(Application.Transpose(Application.Transpose(.Cells(n, "A").Resize(1, 2).Value)), "")
str1 = str2 & Join(Application.Transpose(Application.Transpose(.Cells(n, "C").Resize(1, LCol).Value)), "##") & "##"
str1 = Replace(str1, "=", vbNullString)
str1 = Replace(str1, "####", "##")
Print #2, str1
End with
end sub

You could replace your line:
str1 = Replace(str1, "####", "##")
with:
Do Until Len(str1) = Len(Replace(str1, "####", "##"))
str1 = Replace(str1, "####", "##")
Loop
which will keep applying the replace until there is no point in doing so (i.e. the length doesn't change)
EDIT
Sorry to alter an accepted answer, but I've noticed that you might want to keep instances of #### if they occur somewhere other than at the end of the row. If you do then the following would be better, as it only trims the right-most characters:
Do Until Right(str1, 4) <> "####"
str1 = Left(str1, Len(str1) - 2)
Loop

The reason you are getting repeated characters is because you are joining empty array elements. An alternative to removing repeated delimiters is to use a UDF to only join non null values. Please see below for such a function.
Sub TestJoin()
Dim r As Range: Set r = Worksheets("Sheet1").Range("B1:B12")
Dim arr() As Variant
arr = Application.Transpose(r)
Debug.Print NonNullJoin(arr, "#") & "#"
End Sub
Function NonNullJoin(SourceArray() As Variant, Optional Delimiter As String = " ") As String
On Error Resume Next
Dim i As Long: For i = 0 To UBound(SourceArray)
If CStr(SourceArray(i)) <> "" Then NonNullJoin = _
IIf(NonNullJoin <> "", NonNullJoin & Delimiter & CStr(SourceArray(i)), CStr(SourceArray(i)))
Next i
End Function

Use regex to replace more than one instance.
Note:
If you want to replace repeats only at the end of the string then change regex pattern to (##){2,}$ . This will deal with 2 or more occurrences.
If only worried about two occurrences at end, use (##)\1$
Code:
Option Explicit
Sub TEST()
Dim testString As String, pattern As String
testString = "xxxxx####"
testString = RemoveChars(testString)
Debug.Print testString
End Sub
Public Function RemoveChars(ByVal inputString As String) As String
Dim regex As Object, tempString As String
Set regex = CreateObject("VBScript.RegExp")
With regex
.Global = True
.MultiLine = True
.IgnoreCase = False
.pattern = "(##){2,}"
End With
If regex.TEST(inputString) Then
RemoveChars = regex.Replace(inputString, "##")
Else
RemoveChars = inputString
End If
End Function

Related

How to replace string with value contained in cells?

I have a column containing formulas as "strings", i.e. "=+I11+I192+I245+I280"
I need to replace the cells (I11, I192,I245andI280`) ID with the content (strings) contained in the cells themselves.
Example:
Cell X --> "=+I11+I192+I245+I280"
Cell I11 = 'A'
Cell I192 = 'B'
Cell I245 = 'C'
Cell I280 = 'D'
The formula should generate "=+A+B+C+D".
This?
="=+" & I11 &"+" & I192 &"+" & I245 & "+" & I280
Well, how about :
=I11 & I192 & I245 & I280
Or you can include spaces
=I11 & " " & I192
But straight quotes - my phone is being funny...
The formula should generate --> "=+A+B+C+D"
Try,
="=+"&textjoin("+", true, I11, I192, I245, I280)
Don't know what you will be doing with empty cells so here is draft
Public Sub test()
[I11] = "A": [I192] = "B": [I245] = "C": [I280] = "D"
Debug.Print ConvertedString("=+I11+I192+I245+I280")
End Sub
Public Function ConvertedString(ByVal inputString As String) As Variant
Dim arr() As String, i As Long
On Error GoTo errHand
If Not InStr(inputString, Chr$(43)) > 0 Then
ConvertedString = CVErr(xlErrNA)
Exit Function
End If
arr = Split(inputString, Chr$(43))
For i = 1 To UBound(arr)
arr(i) = Range(arr(i))
Next i
ConvertedString = Join(arr, Chr$(43))
Exit Function
errHand:
ConvertedString = CVErr(xlErrNA)
End Function
I think you mean something like
=INDIRECT(I11,TRUE)+INDIRECT(I192,TRUE)+INDIRECT(I245,TRUE)+INDIRECT(I280,TRUE)
but please note that Indirect is a volatile function, and can slow your calculations down if used extensively.
Using VBA (with only single delimiter):
Function ReplaceAddr(sInput As String, Optional sDelimiter As String = "+") As String
Dim sArr
Dim i As Long
sArr = Split(sInput, sDelimiter)
For i = 1 To UBound(sArr)
sArr = Range(sArr(i))
Next i
ReplaceAddr = Join(sArr, sDelimiter)
End Function
From OP's comment:
The problem is that formulas changes, so I can't only change manually. The one I gave you is only an example, but I have so many different ones with all math operators.
You can try finding cell addresses with regular expression and replace with cell's value:
Function ReplaceAddr2(sInput As String) As String
Dim oRegEx As Object
Dim oMatches As Object
Dim i As Long, lStart As Long, lLength As Long
Set oRegEx = CreateObject("vbscript.regexp")
oRegEx.Pattern = "[A-Za-z]{1,3}\d{1,7}"
oRegEx.Global = True
oRegEx.MultiLine = True
Set oMatches = oRegEx.Execute(sInput)
lStart = 0
For i = 0 To oMatches.Count - 1
lLength = oMatches(i).FirstIndex - lStart
ReplaceAddr2 = ReplaceAddr2 & Mid$(sInput, lStart + 1, lLength) & Range(oMatches(i).Value)
lStart = lStart + lLength + oMatches(i).length
Next
ReplaceAddr2 = ReplaceAddr2 & Mid(sInput, lStart + 1, Len(sInput) - lStart)
End Function
Pattern is 1-3 letters followed by 1-7 digits.
Both functions are not volatile - will be recalculated only when input string changes, but not when cells addressed there change. Adding this line:
Application.Volatile True
will make it recalculate on every change, but it may affect performance.

How to remove modify a string to remove letters from a new worksheet

So I've been trying to create a Macro to format the open a new workfile and then modify 1 colomn to remove the letters from the string of number (20180717a to become 20180717 for example).
I've tried several things and came up with this code, but it doent seem to work properly:
Sub Creating_progress_reports()
Dim wb As Workbook
Dim myfilename As String
myfilename = "xxxx.xlsx"
Set wb = Workbooks.Open(myfilename)
Dim str1 As String
Dim str2 As String
Dim rngTemp As Range
Dim rngCell As Range
str1 = "a"
str2 = "b"
str3 = "c"
str4 = "d"
With Workbooks("xxxx.xlsx").Sheets("xxxx")
Set rngTemp = Columns(6).CurrentRegion
For Each rngCell In rngTemp
If InStr(1, rngCell, str1) > 0 Then
rngCell = Replace(rngCell.Value, str1, "")
End If
If InStr(1, rngCell, str2) > 0 Then
rngCell = Replace(rngCell.Value, str2, "")
End If
If InStr(1, rngCell, str1) > 0 Then
rngCell = Replace(rngCell.Value, str3, "")
End If
If InStr(1, rngCell, str1) > 0 Then
rngCell = Replace(rngCell.Value, str4, "")
End If
Next rngCell
End With
End Sub
The error is that the vba code goes through, but the results are not there. The letters in the strings are still there.
You need a . before Columns(6).CurrentRegion to refer to the Workbooks("xxxx.xlsx").Sheets("xxxx"):
With Workbooks("xxxx.xlsx").Sheets("xxxx")
Set rngTemp = .Columns(6).CurrentRegion
Otherwise it is referring to one of the following:
the Sheet in which the code is located;
ActiveSheet, if the code is not inside a Sheet;

How to extract numbers from a text string in VBA [duplicate]

This question already has answers here:
Excel UDF for capturing numbers within characters
(4 answers)
Closed 4 years ago.
I need to extract the numbers from a string of text and I'm not quite sure how to do it. The code I've attached below is very preliminary and most likely can be done more elegantly. A sample of the string I'm trying to parse is as follows:
"ID CSys ID Set ID Set Value Set Title 7026..Plate Top MajorPrn Stress 7027..Plate Top MinorPrn Stress 7033..Plate Top VonMises Stress"
I need to pull the numbers 7026, 7027, and 7033. The string will vary in length and the number of values that I'll need to pull will also vary. Any help would be much appreciated. Thanks!
Dim WrdArray() As String
Dim txtstrm As TextStream
Dim line As String
Dim clm As Long
Dim Rw As Long
'------------------------------------------------------------
Dim i As Long
Dim strPath As String
Dim strLine As String
Dim count, count1 As Integer
Dim holder As String
Dim smallSample As String
count = 0
count1 = 1
holder = ""
'Remove Filters and Add Custom Filters
Call Application.FileDialog(msoFileDialogOpen).Filters.Clear
Call Application.FileDialog(msoFileDialogOpen).Filters.Add("Text Files", "*.txt")
Call Application.FileDialog(msoFileDialogOpen).Filters.Add("Dat Files", "*.dat")
'only allow the user to select one file
Application.FileDialog(msoFileDialogOpen).AllowMultiSelect = False
'make the file dialog visible to the user
intChoice = Application.FileDialog(msoFileDialogOpen).Show
'determine what choice the user made
If intChoice <> 0 Then
'get the file path selected by the user
strPath = Application.FileDialog(msoFileDialogOpen).SelectedItems(1)
End If
'------------------------------------------------------------
If strPath <> "" Then
Set txtstrm = FSO.OpenTextFile(strPath)
Else
MsgBox "No file selected.", vbExclamation
Exit Sub
End If
Rw = 1
Do Until txtstrm.AtEndOfStream
line = txtstrm.ReadLine
clm = 1
WrdArray() = Split(line, " ") 'Change with ; if required
For Each wrd In WrdArray()
If Rw = 1 Then
Do While count <> Len(wrd)
smallSample = Left(wrd, 1)
If smallSample = "0" Or smallSample = "1" Or smallSample = "2" Or smallSample = "3" Or smallSample = "4" _
Or smallSample = "5" Or smallSample = "6" Or smallSample = "7" Or smallSample = "8" _
Or smallSample = "9" Then
holder = holder & smallSample
Else
If holder <> "" Then
Cells(count1, 1) = holder
count1 = count1 + 1
End If
holder = ""
End If
wrd = Right(wrd, Len(wrd) - 1)
clm = clm + 4
ActiveSheet.Cells(Rw, clm) = holder
Loop
Else
ActiveSheet.Cells(Rw, clm) = wrd
clm = clm + 1
End If
Next wrd
Rw = Rw + 1
Loop
txtstrm.Close
End Sub
You can use Regular Expressions.
Sub ExtractNumbers()
Dim str As String, regex As regExp, matches As MatchCollection, match As match
str = "ID CSys ID Set ID Set Value Set Title 7026..Plate Top MajorPrn Stress 7027..Plate Top MinorPrn Stress 7033..Plate Top VonMises Stress"
Set regex = New regExp
regex.Pattern = "\d+" '~~~> Look for variable length numbers only
regex.Global = True
If (regex.Test(str) = True) Then
Set matches = regex.Execute(str) '~~~> Execute search
For Each match In matches
Debug.Print match.Value '~~~> Prints: 7026, 7027, 7033
Next
End If
End Sub
Make sure you reference the VBA regex library:
Open VBA editor
Tools > References...
Check Microsoft VBScript Regular Expression 5.5
To exact numbers in the form you want, try something like:
Sub dural()
Dim s As String, i As Long, L As Long, c As String, temp As String
s = [A1]
L = Len(s)
temp = ""
For i = 1 To L
c = Mid(s, i, 1)
If c Like "[0-9]" Then
temp = temp & c
Else
temp = temp & " "
End If
Next i
temp = "'" & Application.WorksheetFunction.Trim(temp)
temp = Replace(temp, " ", ",")
[B1] = temp
End Sub
You can use this function that splits the "words and test for numeric:
Function numfromstring(str As String) As String
Dim strarr() As String
str = Replace(str, ".", " ")
strarr = Split(str)
Dim i As Long
For i = 0 To UBound(strarr)
If IsNumeric(strarr(i)) Then
numfromstring = numfromstring & "," & strarr(i)
End If
Next i
numfromstring = Mid(numfromstring, 2)
End Function
You would call it from the worksheet with a formula:
=numfromstring(A1)
Or from vba like this:
Sub try()
Dim str As String
str = "ID CSys ID Set ID Set Value Set Title 7026..Plate Top MajorPrn Stress 7027..Plate Top MinorPrn Stress 7033..Plate Top VonMises Stress"
Dim out As String
out = numfromstring(str)
Debug.Print out
End Sub
If you have Office 365 Excel you can use this array formula:
=TEXTJOIN(",",TRUE,IF(ISNUMBER(--TRIM(MID(SUBSTITUTE(SUBSTITUTE(A1,"."," ")," ",REPT(" ",99)),(ROW($1:$100)-1)*99+1,99))),TRIM(MID(SUBSTITUTE(SUBSTITUTE(A1,"."," ")," ",REPT(" ",99)),(ROW($1:$100)-1)*99+1,99)),""))
Being an array formula it needs to be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode:

Removing Duplicate values from a string in VBA

In VBA if I have a string of numbers lets say ("1,2,3,4,5,2,2"), how can I remove the duplicate values and only leave the first instance so the string says ("1,2,3,4,5").
Here is a function you can use to dedupe a string as you've described. Note that this won't sort the deduped string, so if yours was something like "4,2,5,1,3,2,2" the result would be "4,2,5,1,3". You didn't specify you needed it sorted, so I didn't include that functionality. Note that the function uses , as the default delimiter if not specified, but you can specify a delimiter if you choose.
Function DeDupeString(ByVal sInput As String, Optional ByVal sDelimiter As String = ",") As String
Dim varSection As Variant
Dim sTemp As String
For Each varSection In Split(sInput, sDelimiter)
If InStr(1, sDelimiter & sTemp & sDelimiter, sDelimiter & varSection & sDelimiter, vbTextCompare) = 0 Then
sTemp = sTemp & sDelimiter & varSection
End If
Next varSection
DeDupeString = Mid(sTemp, Len(sDelimiter) + 1)
End Function
Here's some examples of how you would call it:
Sub tgr()
MsgBox DeDupeString("1,2,3,4,5,2,2") '--> "1,2,3,4,5"
Dim myString As String
myString = DeDupeString("4-2-5-1-3-2-2", "-")
MsgBox myString '--> "4-2-5-1-3"
End Sub
I suggest writing a Join function to combine the unique parts back into a single string (there is one available for arrays, but not for any other collection):
Function Join(Iterable As Variant, Optional Delimiter As String = ",") As String
Dim notFirst As Boolean
Dim item As Variant
For Each item In Iterable
If notFirst Then
Join = Join & Delimiter
Else
notFirst = True
End If
Join = Join & item
Next
End Function
Then, use Split to split a string into an array, and Scripting.Dictionary to enforce uniqueness:
Function RemoveDuplicates(s As String, Optional delimiter As String = ",") As String
Dim parts As String()
parts = Split(s,delimiter)
Dim dict As New Scripting.Dictionary
Dim part As Variant
For Each part In parts
dict(part) = 1 'doesn't matter which value we're putting in here
Next
RemoveDuplicates = Join(dict.Keys, delimiter)
End Function
try this:
Sub test()
Dim S$: S = "1,2,3,4,5,2,2,5,6,6,6"
Dim Dic As Object: Set Dic = CreateObject("Scripting.Dictionary")
Dim Key As Variant
For Each Key In Split(S, ",")
If Not Dic.exists(Trim(Key)) Then Dic.Add Trim(Key), Nothing
Next Key
S = Join(Dic.Keys, ","): MsgBox S
End Sub
Heres my crack at it:
Function Dedupe(MyString As String, MyDelimiter As String)
Dim MyArr As Variant, MyNewArr() As String, X As Long, Y As Long
MyArr = Split(MyString, MyDelimiter)
ReDim MyNewArr(0)
MyNewArr(0) = MyArr(0)
Y = 0
For X = 1 To UBound(MyArr)
If InStr(1, Join(MyNewArr, MyDelimiter), MyDelimiter & MyArr(X)) = 0 Then
Y = Y + 1
ReDim Preserve MyNewArr(Y)
MyNewArr(Y) = MyArr(X)
End If
Next
Dedupe = Join(MyNewArr, MyDelimiter)
End Function
Call it like this in code:
Dedupe(Range("A1").Text,",")
Or like this in the sheet:
=Dedupe(A1,",")
The first parameter is the cell to test and the second is the delimiter you want to use (in your example it is the comma)
vb6,Find Duplicate letter in word when there is no delimiter.
Function RemoveDuplicateLetter(ByVal MyString As String) As String
Dim MyArr As Variant, MyNewArr() As String, X As String,str as String
Dim bValue As Boolean
Dim i As Long, j As Long
For i = 0 To Len(MyString)
str = str & Mid$(MyString, i + 1, 1) & vbNullChar
Next
i = 0
MyArr = Split(str, vbNullChar)
ReDim MyNewArr(0)
MyNewArr(0) = MyArr(0)
For i = LBound(MyArr) To UBound(MyArr)
bValue = True
For j = i + 1 To UBound(MyArr)
If MyArr(i) = MyArr(j) Then
bValue = False
Exit For
End If
Next
If bValue Then X = X & " " & MyArr(i)
Next
RemoveDuplicateLetter = X
End Function

Select and Remove Characters

I'm trying to remove remove the string that the user enter and the next 16 characters after this string... When I'm removing just the string that I enter, it's working, but when I ask to remove the others next 16 characters it's stop to work. Could some one help me?
The file is:
04_03(+16 characters) text 04_03(+16characters)
04_03(+16 characters) text 04_03(+16characters) text 04_03(+16characters)
text 04_03(+16characters)
The user enters:
strSearch = 04_03
I would like to delete the string 04_03 more the next 16 characters after this string, independetly which characters they are from the file.
The final file should be:
text
text text
text
Global strSearch As String
Global strLenght As Double
Function RegExpReplace(ByVal WhichString As String, _
ByVal pattern As String, _
ByVal ReplaceWith As String, _
Optional ByVal IsGlobal As Boolean = True, _
Optional ByVal IsCaseSensitive As Boolean = True) As String
'Declaring the object
Dim objRegExp As Object
'Initializing an Instance
Set objRegExp = CreateObject("vbscript.regexp")
'Setting the Properties
objRegExp.Global = IsGlobal
objRegExp.pattern = pattern
objRegExp.IgnoreCase = Not IsCaseSensitive
'Execute the Replace Method
RegExpReplace = objRegExp.Replace(WhichString, ReplaceWith)
End Function
Sub findCharacter()
strSearch = InputBox("How starts the text that you would like to remove?", "Character's Search")
If strSearch = "" Then Exit Sub
End Sub
Sub RemoveCharacters()
Dim pattern As String
Dim str As String
Dim u As String
With Sheets("Sheet1")
.Select
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For Lrow = 1 To Lastrow Step 1
str = Cells(Lrow, 1).Value
pattern = strSearch + " [\w \W \s] {16}"
Cells(Lrow, 1).Value = RegExpReplace(str, pattern, "")
Next Lrow
End With
End Sub
Is this what you are trying?
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long, pos As Long, i As Long, n As Long
Dim strToRepl As String, strSearch As String
strSearch = InputBox("How does the text start that you would like to remove?", "Character's Search")
If strSearch = "" Then Exit Sub
'~~> Change this to the relevant sheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 1 To lRow
pos = InStr(1, .Range("A" & i).Value, strSearch, vbTextCompare)
If pos > 0 Then
n = Len(.Range("A" & i).Value) - pos
If Not Len(strSearch) + 16 > n Then
strToRepl = Mid(.Range("A" & i).Value, pos, Len(strSearch) + 16)
.Range("A" & i).Value = Replace(.Range("A" & i).Value, strToRepl, "")
End If
End If
Next i
End With
End Sub
Screenshot