I am using the find and replace function and a vba code in Excel. I want to replace all strings like "/15" by ".15" but only if "/15" is not followed by any other characters. Is there an operator for my need?
For example if I replace all "/15" it also replaces this string if it is followed by other characters.
10/15/15 -> 10.15.15
But what I want is
10/15/15 -> 10/15.15
Cheers
You could use regular expressions, a wealth of stuff on the net about that.
Or something in VBA like so, no real need for a2, could grab the last of a1 before hand, but just to show you difference in the arrays in the locals window.
Function test(strInput As String)
Dim a1() As String
Dim a2() As String
a1 = Split(strInput, "/")
a2 = a1
ReDim Preserve a2(UBound(a1) - 1)
test = Join(a2, "/") & "." & a1(UBound(a1))
End Function
or it can be done using a formula
=SUBSTITUTE(A1,"/",".",(LEN(A1)-LEN(SUBSTITUTE(A1,"/",""))))
I think you should use the function Right for this, to avoid replacing the "/15" in the middle of the string.
Public Function ReplaceRight(strInput As String) As String
If Right(strInput, 3) = "/15" Then
ReplaceRight = Left(strInput, Len(strInput) - 3) & ".15"
Else
ReplaceRight = strInput
End If
End Function
With Excel Formula:
=IF(RIGHT(F215,3)="/15",LEFT(F215,LEN(F215)-3)&".15",F215)
Related
I have a String in VBA with this text: < History Version="1.10" Client="TestClient001" >
I want to get this TestClient001 or anything that's inside Client="xxxx"
I made this code but it's not working
Client = MID(text,FIND("Client=""",text)+1,FIND("""",text)-FIND("Client=""",text)-1)
Is there a way to specifically get the text inside Client="xxxx"?
There's no such function as Find in VBA - that's a worksheet function. The VBA equivalent is InStr, but I don't think you need to use it here.
The best tool for extracting one string from another in VBA is often Split. It takes one string and splits it into an array based on a delimiting string. The best part is that the delimiter doesn't have to be a single character - you can make it an entire string. In this case, we'd probably do well with two nested Split functions.
Client = Split(Split(text,"Client=""")(1),Chr(34))(0)
The inner Split breaks your text string where it finds "Client="". The (1) returns array element 1. Then the outer Split breaks that returned text where it finds a " character, and returns array element 0 as the final result.
For better maintainability, you may want to use constants for your delimiters as well.
Sub EnclosedTextTest()
Const csFlag1 As String = "Client="""
Const csFlag2 As String = """"
Const csSource As String = "< History Version=""1.10"" Client=""TestClient001"" >"
Dim strClient As String
strClient = Split(Split(csSource, csFlag1)(1), csFlag2)(0)
Debug.Print strClient
End Sub
However, if the Split method doesn't work for you, we can use a method similar to the one you were using, with InStr. There are a couple of options here as well.
InStr will return the position in a string that it finds a matching value. Like Split, it can be given an entire string as its delimiter; however, if you use more than one character you need to account for the fact that it will return where it finds the start of that string.
InStr(1,text,"Client=""")
will return 26, the start of the string "Client="" in the text. This is one of the places where it's helpful to have your delimiter stored in a constant.
intStart = InStr(1,text,csFlag1)+len(csFlag1)
This will return the location it finds the start of the delimiter, plus the length of the delimiter, which positions you at the beginning of the text.
If you store this position in a variable, it makes the next part easier as well. You can use that position to run a second InStr and find the next occurrence of the " character.
intEnd = InStr(intStart,text,csFlag2)
With those values, you can perform your mid. You code overall will look something like this:
Sub InstrTextTest()
Const csFlag1 As String = "Client="""
Const csFlag2 As String = """"
Const csSource As String = "< History Version=""1.10"" Client=""TestClient001"" >"
Dim strClient As String
Dim intPos(0 To 1) As Integer
intPos(0) = InStr(1, csSource, csFlag1) + Len(csFlag1)
intPos(1) = InStr(intPos(0), csSource, csFlag2)
strClient = Mid(csSource, intPos(0), intPos(1) - intPos(0))
Debug.Print strClient
End Sub
This will work, but I prefer the Split method for ease of reading and reuse.
You can make use of Split function to split at character = then with last element of the resulting array remove character quotes and > with help of replace function and you will get the required output.
In the end I got it thanks to the idea given by #alok and #Bigben
Dim cl() As String
Dim ClientCode As String
If (InStr(1, temp, "Client=", vbTextCompare) > 0) Then
cl = Split(temp, "=")
ClientCode = cl(UBound(cl))
ClientCode = Replace(ClientCode, """", "")
ClientCode = Replace(ClientCode, ">", "")
It's XML, so you could do this:
Dim sXML As String
sXML = "<History Version=""1.10"" Client=""TestClient001"">"
With CreateObject("MSXML.Domdocument")
.LoadXML Replace(sXML, ">", "/>") 'close the element
Debug.Print .FirstChild.Attributes.getnameditem("Client").Value
End With
I'm trying to create a user defined function that returns everything to the left of the last hyphen in a string. All strings will be formatted like this:
CT2986-400427-15
J84705-202001-12
TF230068-003
DS2112-000038-11
This is my current code, but it keeps displaying a #VALUE! error in the cell. Any ideas?
Function PartNOSUFFIX(PartNo As String) As String
PartNOSUFFIX = Left(PartNo, InStr(8, PartNo, "-") - 1)
End Function
Thanks in advance!
You want to use Instrrev instead which is Instr but in reverse. This way it will always find the last hyphen and return it's position.
So try:
Function PartNOSUFFIX(PartNo As String) As String
PartNOSUFFIX = Left(PartNo, InStrRev(PartNo, "-") - 1)
End Function
You will get a #VALUE! error if the cell is blank or doesn't have a hyphen in it. If you want to account for that you can use something like this instead:
Function PartNOSUFFIX(PartNo As String) As String
If PartNo = "" Or InStr(PartNo, "-") = 0 Then
PartNOSUFFIX = ""
Else
PartNOSUFFIX = Left(PartNo, InStrRev(PartNo, "-") - 1)
End If
End Function
I just made it return blank if the cell it's looking at is blank or doesn't have a hyphen. You can change that to whatever you want it to say of course.
A bit complicated but fun try
Function PartNOSUFFIX(PartNo As String) As String
PartNOSUFFIX = Replace(PartNo, "-" & Split(PartNo, "-")(UBound(Split(PartNo, "-"))), "")
End Function
You can use StrReverse() and Split() to accomplish this quite easily:
Function PartNOSUFFIX(PartNo As String) As String
PartNOSUFFIX = StrReverse(Split(StrReverse(PartNo), "-", 1)(0))
End Function
Alternatively, you can use a regular expression:
Function PartNOSUFFIX(PartNo As String) As String
With CreateObject("vbscript.regexp")
.Pattern = "(.*)-.*"
PartNOSUFFIX = .Replace(PartNo, "$1")
End With
End Function
(.*) - Capture 0+ (greedy) characters other than newline in a capture group upto;
- - A literal hyphen.
.* - Again 0+ (greedy) characters other than newline.
The fact that regular expressions start matching left to right assures that our 1st greedy pattern will consume all characters upto the last hyphen since no other characters come after that leading to the next hyphen.
Note that both options would work even no hyphen is present.
is there a way to check if the string begins with any 4 letters. I am looking for something like this:
If string like "####*" then
'DO STUFF
end if
"#" is for digits, I need the same thing but for letters only.
Can this be done without regEx?
I don't know a way to do this without using regular expressions. We can try using regex Test along with the pattern ^[A-Z]{4}.*$:
Dim input As String
Dim regex As Object
Set regex = New RegExp
regex.Pattern = "^[A-Z]{4}.*$"
input = "ABCD blah"
If regex.Test(input) Then
'DO STUFF
End If
You can do it with Like almost the same as with RegEx.
"{#}" - doesn't exist in Like operators, but "[A-Z]" absolutely valid
if string like "[A-Z][A-Z][A-Z][A-Z]*" then
'DO STUFF
end if
Can this be done without regEx?
Yes, there is no specific need for Regular Expressions since the Like operator is quite capable as some sort of last resort to handle the situation, just like the writer of this article explains. Also, RegEx is sort of slow on a larger database. Nonetheless, RegEX is a great tool to use!
The solution provided by #AlexandruHapco would tell you if the string starts with 4 capital letters. But to account for lower OR upper, you can extend this logic:
If str Like "[a-zA-Z][a-zA-Z][a-zA-Z][a-zA-Z]*" Then
However, to shorten this a bit we can use [!charlist] to tell the operator we are looking for something that is NOT in the provided range. In other words, we could use:
If str Like "[!0-9][!0-9][!0-9][!0-9]*" Then
This last solution won't work when your string has any other characters than alphanumeric ones.
Approach using the FilterXML function
The WorksheetFunction FilterXML() has been added in ►Excel 2013 and allows to specify any XPath search string for a given XML document, which hasn't to be a locally saved file (needing WebService() function), but can be a string within well formed opening and closing nodes, i.e. our test string with some easy node additions (partly comparable to a html structure).
Example call
Sub TextXML()
Dim myString As String
myString = "ABCD blah"
If check(myString) Then
'DO STUFF
Debug.Print "okay"
Else
Debug.Print "oh no"
End If
End Sub
Help function
Function check(ByVal teststring As String) As Boolean
Const s As String = Chr(185) ' unusual character, e.g. Chr(185): "¹"
On Error GoTo oops
If Len(WorksheetFunction.FilterXML("<all><i>" & teststring & "</i></all>", "//i[substring(translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','" & _
String(26, s) & "'),1,4)='" & String(4, s) & "']")) > 0 Then check = True
Exit Function
oops:
Err.Clear
End Function
tl;tr - how to use VBA in Excel versions before 2013
For the sake of the art the classic way to use XPath via XMLDOM methods:
Example call
Sub TextXML2()
Dim myString As String
myString = "ABCD blah"
If check2(myString) Then
'DO STUFF
Debug.Print "okay"
Else
Debug.Print "oh no"
End If
End Sub
Help functions
Function check2(ByVal teststring As String) As Boolean
' Purpose: check if first 4 characters of a test string are upper case letters A-Z
' [0] late bind XML document
Dim xDoc As Object
Set xDoc = CreateObject("MSXML2.DOMDocument.6.0")
' [1] form XML string by adding opening and closing node names ("tags")
teststring = "<all><i>" & teststring & "</i></all>"
' [2] load XML
If xDoc.LoadXML(teststring) Then
' [3a] list matching item(s) via XPath
Dim myNodeList As Object
Set myNodeList = xDoc.SelectNodes(XPath())
'Debug.Print teststring, " found: " & myNodeList.Length
' [3b] return true if the item matches, i.e. the list length is greater than zero
If myNodeList.Length > 0 Then check2 = True
End If
End Function
Function XPath() As String
' Purpose: create XPath string to get nodes where the first 4 characters are upper case letters A-Z
' Result: //i[substring(translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹'),1,4)="¹¹¹¹"]
' get UPPER case alphabet
Const ABC As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
' define replacement string consisting of an unusual character repeated 26 times
Const UNUSUAL As String = "¹" ' << replace by your preferenced character
Dim replacement As String: replacement = String(Len(ABC), UNUSUAL)
'return XPath string
XPath = "//i[substring(translate(.,'" & ABC & "','" & replacement & "'),1,4)=""" & String(4, UNUSUAL) & """]"
End Function
To test a few characters -- the first 4 letters in this case -- you can always do the following:
If Not (Mid(string, 1, 1) Like "#" And Mid(string, 2, 1) Like "#" _
And Mid(string, 3, 1) Like "#" And Mid(string, 4, 1) Like "#") Then
' DO STUFF
End If
It's a bit more to type then when using the Like operator, but so what? Also, you can use Select Case in a loop...
Another option is to use IsNumeric(Mid(string, i, 1)) instead of Mid(string, i, 1) Like "#", etc.
Granted, this approach is still quite practical with 4 characters, but is not as flexible and very much not scalable like RegEx is.
One of my cells appears to be blank but has a length of 2 characters. I copied the string to this website and it has identified it as a null string.
I have tried using IsNull and IsEmpty, as well as testing to see if it is equivalent to the vbNullString but it is still coming up as False.
How do I identify this string as being Null?
A string value that "appears to be blank but has a length of 2 characters" is said to be whitespace, not blank, not null, not empty.
Use the Trim function (or its Trim$ stringly-typed little brother) to strip leading/trailing whitespace characters, then test the result against vbNullString (or ""):
If Trim$(value) = vbNullString Then
The Trim function won't strip non-breaking spaces though. You can write a function that does:
Public Function TrimStripNBSP(ByVal value As String) As String
TrimStripNBSP = Trim$(Replace(value, Chr$(160), Chr$(32)))
End Function
This replaces non-breaking spaces with ASCII 32 (a "normal" space character), then trims it and returns the result.
Now you can use it to test against vbNullString (or ""):
If TrimStripNBSP(value) = vbNullString Then
The IsEmpty function can only be used with a Variant (only returns a meaningful result given a Variant anyway), to determine whether that variant contains a value.
The IsNull function has extremely limited use in Excel-hosted VBA, and shouldn't be needed since nothing is ever going to be Null in an Excel worksheet - especially not a string with a length of 2.
Chr(160) Issue
160 is the code number of a Non-Breaking Space.
Let us say the cell is A1.
In any cell write =CODE(A1) and in another (e.g. next to) write =CODE(MID(A1,2,1)).
The results are the code numbers (integers e.g. a and b) of the characters.
Now in VBA you can use:
If Cells(1, 1) = Chr(a) & Chr(b) Then
End If
or e.g.
If Left(Cells(1, 1), 1) = Chr(160) then
End If
I have a function which returns value as string.
Function Trimcell(cellvalue As varnant) As String
Trimcell = Replace(CStr(cellvalue), " ", "")
End Function
I want to change the data type string to long . Any help.
Change your function to this:
Function Trimcell(cellvalue As varnant) As Long
Trimcell = Val(Replace(CStr(cellvalue), " ", ""))
End Function
You have a spelling error - varnant instead of Variant.
A better option than using Replace is to use Val which removes blanks, tabs, and linefeed characters from a string and returns a Double. It also stops reading the string at the first non-numeric character apart from period (.) which it recognises as the decimal separator.
As you have declared cellvalue As Variant you shouldn't need CStr either.
Function Trimcell2(cellvalue As Variant) As Long
Trimcell = Val(cellvalue)
End Function