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
Related
In Excel VBA, how to replace all sub-strings of xyz(*)in a string which contains several instances of this sub-string?
* in xyz(*) means every thing in between the two parenthesis. For example the string is "COVID-19 xyz(aaa) affects xyz(bbbbbb) so much families." This changes to "COVID-19 affects so much families."
You should use a regular expression.
for example:
Sub a()
Dim Regex As New RegExp
Dim SubjectString As String
SubjectString = "COVID-19 xyz(test) affects xyz(test) so much, families."
With Regex
.Global = True
.Pattern = "(\sxyz(\S*))"
End With
Dim ResultString As String
ResultString = Regex.Replace(SubjectString, "")
MsgBox (ResultString)
End Sub
the first \s used to grab 1 whitespace before the xyz, so when you delete replace, it won't leave 2 white spaces. <br> then looking for the string xyz and the opening parenthesis, inside it I look for \S which is any char and * means 0 or more times and then I look for the closing parenthesis.
here's a solution avoiding regexp, which I tend to avoid whenever possible and convenient (as this case seems to me)
Dim s As String
s = "COVID-19 xyz(aaa) affects xyz(bbbbbb) so much families."
Dim v As Variant
For Each v In Filter(Split(s, " "), "xyz(")
s = Replace(s, v & " ", vbNullString)
Next
I got the use of Filter() from this post
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.
Dim textstring as String,warray() as String
textstring=Range("A3").Value
warray=split(textstring,"")
If isDate(warray(0))=True Then
Range("A4").Value=warray(1)
End If
This code displays only one word, no other words are displayed.
Typically, the vba Split function is used to split a string into a multiple element array on a delimiter. If a space was used as the delimiter, a sentence or paragraph would be split into individual words.
You are providing a zero-length string (e.g. "" ) as the delimiter. From the msdn docs:
... If delimiter is a zero-length string, a single-element array containing the entire expression string is returned.
So if you want to actually split something into multiple pieces, you cannot use a zero-length string as the delimiter.
If you used a space as the delimiter and provided no other parameters, then your example would be split into four elements of the array. I suspect you only want to split off the time and leave the show title together. The limit parameter is used for this. A limit of 2 will split your original string into a time and a show title.
Option Explicit
Sub Macro3()
Dim textstring As String, warray() As String
textstring = Range("A3").Value
warray = Split(expression:=textstring, delimiter:=" ", limit:=2)
If IsDate(warray(0)) Then
Range("A4").Value = warray(0)
Range("A5").Value = warray(1)
End If
End Sub
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
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)