Replace string in VBA - vba

sampleString = "Lorem ipsumxolor sit"
I want the immediate left and right characters of x to be blank. The desired output would be "Lorem ipsu x lor sit"
Using stringtext = replace(stringtext, "x", " x "), the output is Lorem ipsum x olor sit. However, the length of the string obviously increases and doesn't match the desired output.
Another limitation is that incase of sampleString = "Lorem ipsumxxxolor sit". I can't use stringtext = replace(stringtext, "x", " x ") as the output becomes Lorem ipsum x x x olor sit instead of the desired result Lorem ipsu xxx lor sit. I can use replace(stringtext, "xxx", " xxx ") but that would cause me to use multiple conditions instead of one single solution.
Is there an efficient way to deal with this?
Thank you!

efficient
Private Function SpaceOutExes(ByVal s As String) As String
SpaceOutExes = s
Dim i As Long
Dim PrevCharIsX As Boolean
PrevCharIsX = Left$(SpaceOutExes, 1) = "x"
For i = 2 To Len(SpaceOutExes)
If Mid$(SpaceOutExes, i, 1) = "x" Then
If Not PrevCharIsX Then Mid$(SpaceOutExes, i - 1, 1) = " "
PrevCharIsX = True
Else
If PrevCharIsX Then Mid$(SpaceOutExes, i, 1) = " "
PrevCharIsX = False
End If
Next
End Function
Dim sampleString As String
sampleString = "Lorem ipsumxolor sit"
Debug.Print SpaceOutExes(sampleString)

You need to cut the original string in pieces and put it together the way you like:
Option Explicit
Public Sub StringExample()
Dim SampleString As String
SampleString = "Lorem ipsumxolor sit"
Dim FoundPosition As Long
FoundPosition = InStr(SampleString, "x")
Dim ResultString As String
ResultString = Left$(SampleString, FoundPosition - 2) & " " & Mid$(SampleString, FoundPosition, 1) & " " & Mid$(SampleString, FoundPosition + 2)
End Sub
Output is then
Lorem ipsu x lor sit
Or for multiple x:
Public Sub StringExampleMulti()
Const Delimiter As String = "x"
Dim SampleString As String
SampleString = "Lorem ipsumxxxolor sit amxet, conse!"
Dim Splitted() As String
Splitted = Split(SampleString, "x")
Dim ResultString As String
Dim i As Long
For i = LBound(Splitted) To UBound(Splitted)
If Splitted(i) <> vbNullString Then
If i = LBound(Splitted) Then
ResultString = Left$(Splitted(i), Len(Splitted(i)) - 1) & " " & Delimiter
ElseIf i = UBound(Splitted) Then
ResultString = ResultString & Delimiter & " " & Right$(Splitted(i), Len(Splitted(i)) - 1)
Else
ResultString = ResultString & " " & Mid$(Splitted(i), 2, Len(Splitted(i)) - 2) & " "
End If
Else
ResultString = ResultString & Delimiter
End If
Next i
Debug.Print ResultString
End Sub
outputs:
Lorem ipsu xxx lor sit a x t, conse!

Related

In VBA, How can I trim any characters not just whitespaces?

Due to some other sloppy coding, I need to remove leading or trailing vbCrLf or reduce any instances of more than one consecutive vbCrLf to a single line.
So how can I execute the trim function, but to trim a character other than " " ?
Here are functions to do just that
Function TrimAny(ByVal myString As String, myTrim As String) As String
If myString = "" Or myTrim = "" Then TrimAny = myString: Exit Function
While inStB(myString, myTrim & myTrim): myString = Replace(myString, myTrim & myTrim, myTrim): Wend
myString = TrimStart(myString, myTrim)
myString = TrimEnd(myString, myTrim)
TrimAny = myString
End Function
Function TrimEnd(ByVal myString As String, myTrim As String) As String
If myString = "" Or myTrim = "" Then TrimEnd = myString: Exit Function
While Right(myString, Len(myTrim)) = myTrim: myString = Left(myString, Len(myString) - Len(myTrim)): Wend
TrimEnd = myString
End Function
Function TrimStart(ByVal myString As String, myTrim As String) As String
If myString = "" Or myTrim = "" Then TrimStart = myString: Exit Function
While Left(myString, Len(myTrim)) = myTrim: myString = Right(myString, Len(myString) - Len(myTrim)): Wend
TrimStart = myString
End Function
Solution with RegExp:
Function CrLfTrim(ByVal text As String) As String
' set a reference to 'Microsoft VBScript Regular Expression 5.5' in Tools->References VBE menu
Static re As RegExp ' re is Static and stores the object between function calls, so there is no need to create it each time
If re Is Nothing Then ' it is only necessary to create re if it is Nothing (first time)
Set re = New RegExp
re.Global = True
End If
With re
.Pattern = "(^(\x0D\x0A)+)|((\x0D\x0A)+$)" 'set pattern to remove leading and trailing vbCrLf
text = .Replace(text, "") 'remove leading and trailing vbCrLf
.Pattern = "(\x0D\x0A){2,}" 'set the pattern for the internal sequential vbCrLf
CrLfTrim = .Replace(text, vbCrLf) ' replace the internal sequential vbCrLf with one vbCrLf
End With
End Function
Usage example:
Sub Example()
Dim txt As String: txt = vbCrLf & "Lorem ipsum dolor sit " & vbCrLf & vbCrLf & vbCrLf & "amet, consectetur " & vbCrLf & vbCrLf
Debug.Print "Before: [" & txt & "]"
Debug.Print "After: [" & CrLfTrim(txt) & "]"
End Sub
Prints:
Before: [
Lorem ipsum dolor sit
amet, consectetur
]
After: [Lorem ipsum dolor sit
amet, consectetur ]

VBA, 2nd last "/" using InstrRev

I have code that parses out the last word on a string.
ie. Stack/Over/Flow will give me "Flow".
But I want to get "Over/Flow".
This is what I got, but only able to get "Flow"
arr(counter - 2) = "'" & mid(Text, InStrRev(Text, "/") + 1) & "'"
I would use Split()
Sub lastTwo()
Dim str As String
str = "Stack/Over/Flow"
Dim splt() As String
splt = Split(str, "/")
If UBound(splt) > 0 Then
Debug.Print splt(UBound(splt) - 1) & "/" & splt(UBound(splt))
End If
End Sub
Here is a function that does it:
Function lastParts(str As String, delim As String, x As Long) As String
Dim splt() As String
splt = Split(str, "/")
If UBound(splt) + 1 >= x Then
Dim t As String
t = "=INDEX(INDEX({""" & Join(splt, """;""") & """},N(IF({1},ROW(" & UBound(splt) - x + 2 & ":" & UBound(splt) + 1 & "))),),)"
lastParts = Join(Application.Transpose(Application.Evaluate(t)), delim)
Else
lastParts = str
End If
End Function
It has three parts, the string, the delimiter and the number of returns.
It can be called using your code:
arr(counter-2) = lastParts(Text,"/",2)
or from the worksheet
=lastParts(A1,"/",2)
Initially misread the question. You can nest InStrRev() calls
arr(counter - 2) = "'" & mid(Text, InStrRev(Text, "/",InStrRev(Text, "/")-1)+1) & "'"

Separate data with similar starting letters in different cells

I have following data in cell A1 -
EP10101010 | EP202020 | EP300005 | US789456 | US876543 | NZ90876 | LP98789 | LP88888
I want values that are starting with the same characters (e.g. EP) to be separated and grouped in one cell.
Desired output:
Cell A2 - EP10101010 | EP202020 | EP300005
Cell A3 - US789456 | US876543
Cell A4 - NZ90876
Cell A5 - LP98789 | LP88888
you could try this:
Sub main()
Dim strng As Variant, strngs As Variant
Dim lastStrngID As String, resStrng As String
Dim rowIndex As Long
strngs = Split(Replace(Range("A1"), " ", ""), "|")
rowIndex = 2
lastStrngID = Left(strngs(0), 2)
For Each strng In strngs
If Left(strng, 2) <> lastStrngID Then
Cells(rowIndex, 1).Value = Left(resStrng, Len(resStrng) - 1)
rowIndex = rowIndex + 1
lastStrngID = Left(strng, 2)
resStrng = strng & " | "
Else
resStrng = resStrng & strng & "|"
End If
Next
Cells(rowIndex, 1).Value = Left(resStrng, Len(resStrng) - 1)
End Sub
or, alternatively:
Sub main2()
Dim strng As Variant
With CreateObject("Scripting.Dictionary")
For Each strng In Split(Replace(Range("A1"), " ", ""), "|")
.Item(Left(strng, 2)) = .Item(Left(strng, 2)) & "|" & strng & "|"
Next
Range("A2").Resize(.count).Value = Application.Transpose(.Items)
With Range("A2").Resize(.count)
.Replace "||", "--"
.Replace "|", ""
.Replace "--", " | "
End With
End With
End Sub
I've got this code:
Public Function SplitStart(start As String, text As String) As String
Dim splitString() As String
Dim st As Variant
Dim returnstring As String
Dim i As Integer
Dim trimmed As String
splitString = Split(text, " | ")
returnstring = ""
For Each st In splitString
trimmed = Trim(st)
If Left(trimmed, Len(start)) = start Then
If returnstring <> "" Then
returnstring = returnstring + " | "
End If
returnstring = returnstring + trimmed
End If
Next
SplitStart = returnstring
End Function
You insert it into a module and then you can use
=splitstart("EP";A1)
For example in A2

Converting String into Long for RGB() values

I am writing a macro that recognizes the RGB value of a cell and then passes it as an argument to conditional formatting. The only issue is that using below:
RGBcolor1 = "RGB(" & CInt("&H" & Right(HEXcolor1, 2)) & _
", " & CInt("&H" & Mid(HEXcolor1, 3, 2)) & _
", " & CInt("&H" & Left(HEXcolor1, 2)) & ")"
where:
HEXcolor1 = Right("000000" & Hex(Sheet1.[LowColour].Interior.Color), 6)
The RGB value is a string, whereas in order to pass it as .Color, I need it to be a Long (Color = rgb(255, 0, 0)).
I am aware solutions exist where using Debug window is recommended to retrieve ?rgb(255,0,0), however, I would like to automate the process. I tried Clng() as well as .Evaluate() but they did not work.
Any help greatly appreciated!
You'll have to parse the string. You could use a regex or just make some simple replacements to isolate just the digits. For example:
strColor = "RGB(123, 0, 234)"
strColor = Replace(strColor, "RGB", "")
strColor = Replace(strColor, "(", "")
strColor = Replace(strColor, ")", "")
strColor = Replace(strColor, " ", "")
Dim a As Variant, c As Long
a = Split(strColor, ",")
c = a(0) * &H10000 + a(1) * &H100 + a(2)
Range("A1").Interior.Color = c
Or, with a regex (you'll have to add a reference to the Microsoft VBScript Regular Expressions 5.5 library):
With New RegExp
.Global = True
.Pattern = "[^\d,]" ' Remove anything that's not a digit or comma
Dim a As Variant, c As Long
a = Split(.Replace(strColor, ""), ",")
c = a(0) * &H10000 + a(1) * &H100 + a(2)
End If
Range("A1").Interior.Color = c
Edit:
Here's a quick but hacky way, using Eval() from the Microsoft Script Control:
With CreateObject("MSScriptControl.ScriptControl")
.Language = "VBScript"
Range("A1").Interior.Color = .Eval(strColor)
End With
You can convert it by using the val() function
Dim l as long
dim str as string
str = "111111"
l = val(str)
or
CLng(Val(str))

String to abbreviation

I'm a graphic artist, new to Excel and VBA but trying to use it to process mountains of data in excel to be used as variable data in Illustrator.
If I want to convert cells with product names for signs like "Budwieser, Bud Light & Bud Black Crown" to an abbreviation following the format "Budweiser_BL_BBC"
I have written a function that I thought would accomplish my task but it returns #VALUE!
Edit
To explain the logic: my idea was to take the string, split it on " & " and then split the first position of the resulting array on ", " then adding what was after the "&" to the end of the second array - this array, sProd, has the products separated into different positions of the array.
Then looping through that array and splitting each product at the spaces creating a jagged array.
Then loop through that array again creating a string taking only the first letter of each word in each product, separating products with an underscore. The exception being that the first word of the first product is spelled out and set in proper case. (Just saw an error in my logic and added the code for the first word exception).
Edit #2
The function should return a string with the first word of the original string set in proper case with all other words abbreviated to their first letter and products separated by underscores. So "Budweiser, Bud Light & Bud Light Lime" returns "Budweiser_BL_BLL", "All Coke & Dr Pepper Products" would return "AllC_DPP" and "Gatorade" returns "Gatorade".
This is my first bout with Excel and VBA.
Function Abbrev(p As String) As String
Dim sAmpersand() As Variant
Dim sProd() As Variant
sAmpersand = Split(p, " & ")
sProd = Split(sAmpersand(0), ", ")
sProd(UBound(sProd)) = sAmpersand(1)
Dim ProductCount As Integer
Dim ProductEnd As Integer
ProductEnd = UBound(sProd) - 1
For ProductCount = 0 To ProductEnd
sProd(ProductCount) = Split(sProd(ProductCount), " ")
ProductCount = ProductCount + 1
Next ProductCount
Dim WordCount As Integer
Dim WordEnd As Integer
WordEnd = UBound(sProd(ProductCount)) - 1
Abbrev = StrConv(sProd(0)(0), vbProperCase)
For ProductCount = 0 To ProductEnd
For WordCount = 0 To WordEnd
If ProductCount = 0 Then
WordCount = 1
End If
Abbrev = Abbrev & Left(sProd(ProductCount)(WordCount), 1)
WordCount = WordCount + 1
Next WordCount
If ProductCount + 1 < ProductEnd Then
Abbrev = Abbrev & "_"
End If
ProductCount = ProductCount + 1
Next ProductCount
End Function
Working code:
Function Abbrev(p As String) As String
Dim res As String, w1, w2
res = Split(Split(p, ",")(0), " ")(0)
If res = Split(p, ",")(0) Then res = res & "_"
For Each w1 In Split(Mid(Replace(p, " &", ","), Len(res) + 1), ",")
For Each w2 In Split(w1, " ")
res = res & Left(w2, 1)
Next w2
res = res & "_"
Next w1
Abbrev = IIf(Right(res, 1) <> "_", res, Left(res, Len(res) - 1))
End Function
Here's a better abbreviate function:
Function Abbreviate(Name As String) As String
Dim I As Integer
Dim sResult As String
Dim sTemp As String
I = InStr(Name, " ")
If I < 1 Then
Abbreviate = Name
Exit Function
End If
sResult = Left$(Name, I)
sTemp = Name
Do While I > 0
sTemp = Right$(sTemp, Len(sTemp) - I)
If Left$(sTemp, 1) = "(" Then
If Mid$(sTemp & "***", 3, 1) = ")" Then
sResult = sResult & " " & Left$(sTemp, 3)
Else
sResult = sResult & " " & Left$(sTemp, 1)
End If
Else
sResult = sResult & " " & Left(sTemp, 1)
End If
I = InStr(sTemp, " ")
Loop
Abbreviate = sResult
End Function
This is from user al_b_cnu on mrexcel.com
Here is a modified version to shorten up the result a bit:
Function Abbreviate(Name As String) As String
Dim I As Integer
Dim sResult As String
Dim sTemp As String
I = InStr(Name, " ")
If I < 1 Then
Abbreviate = Name
Exit Function
End If
sResult = Left$(Name, I)
sTemp = Name
Do While I > 0
sTemp = Right$(sTemp, Len(sTemp) - I)
If Left$(sTemp, 1) = "(" Then
If Mid$(sTemp & "***", 3, 1) = ")" Then
sResult = sResult & Left$(sTemp, 3)
Else
sResult = sResult & Left$(sTemp, 1)
End If
Else
sResult = sResult & Left(sTemp, 1)
End If
I = InStr(sTemp, " ")
Loop
Abbreviate = sResult
End Function