Related
I have a string like this one :
"'where CAST(a.DT_NPE_SORTIE as integer ) < cast (add_months (cast (a.dt_nep_restructuration as date format 'YYYYMMDD'), 12) as integer) and a.DT_NPE_SORTIE is not null and a.DT_NPE_SORTIE <> '99991231' and a.dt_npe_restructuration is not null and a.dt_npe_restructuration <> '99991231'"
I need to extract all "a.FIELDNAME" like a.dt_nep_restructuration, a.DT_NPE_SORTIE from the previous screen.
I need to do this in VBA for a project at work.
So far I used If & InStr to check if a list of value is present in the string. But it will be easier for me to extract all a.FIELDNAME then check if they match with fieldname in an array.
Best regards,
jouvzer
I saw there are many with "NPE" and one with "NEP"? Is that a typo? If it is, then will it always start with a.dt_nep_...? – Siddharth Rout 9 mins ago
No it's a typo in order to raise an error for my vba function. It will always start with "a." – Jouvzer 6 mins ago
I have handled both NPE/NEP. Is this what you are trying?
Option Explicit
Private Sub simpleRegex()
Dim strPattern As String: strPattern = "a.dt_(nep|npe)_\w+"
Dim regEx As Object
Dim strInput As String
Dim inputMatches As Object
Dim i As Long
strInput = "'where CAST(a.DT_NPE_SORTIE as integer ) < cast (add_months (cast (a.dt_nep_restructuration as date format 'YYYYMMDD'), 12) as integer) and a.DT_NPE_SORTIE is not null and a.DT_NPE_SORTIE <> '99991231' and a.dt_npe_restructuration is not null and a.dt_npe_restructuration <> '99991231'"
Set regEx = CreateObject("VBScript.RegExp")
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = True
.Pattern = strPattern
End With
Set inputMatches = regEx.Execute(strInput)
If inputMatches.Count <> 0 Then
For i = 0 To inputMatches.Count - 1
Debug.Print inputMatches.Item(i)
Next i
End If
End Sub
Note: If it starts with a.dt then you can also use a.dt_\w+_\w+
Here is one RegExp based code which will print output for cell A1 in immediate window.
Public Sub FindMatches()
Dim oRgEx As Object, oMatches As Object
Dim i As Long
Set oRgEx = CreateObject("VBScript.RegExp")
With oRgEx
.Global = True
.MultiLine = True
.Pattern = "\ba\.[A-z_]+\b"
Set oMatches = .Execute(Range("A1").Value)
If oMatches.Count <> 0 Then
For i = 0 To oMatches.Count - 1
Debug.Print oMatches.Item(i)
Next i
End If
End With
End Sub
Depending on your actual data, you can adjust this further and adapt in your code.
Note: I am a basic level user of RegExp so you may want to consider suggestions indicated below such as \ba\.[A-Za-z_]+\b or \ba\.\w+\b if you get unusual results.
Simple alternative via Filter()
Filtering of all Split() elements in a string array containing the start identification a. allows to receive already a resulting array with all wanted elements (see section a) and b)).
An eventual cosmetic action removes unnecessary characters before the identifying prefix "a." (see section c))
Function ExtractFieldnames(s As String)
Const PREFIX As String = ".a"
'a) split string into tokens
Dim tmp() As String
tmp = Split(s, " ")
'b) leave only elements that include fieldnames
tmp = Filter(tmp, PREFIX, True)
'c) let them start with "a."
Dim i As Long
For i = 0 To UBound(tmp)
tmp(i) = PREFIX & Split(tmp(i), PREFIX)(1)
Next
'd) return array as function result
ExtractFieldnames = tmp
End Function
Example call
Sub TestExtract()
Dim s As String
s = "'where CAST(a.DT_NPE_SORTIE as integer ) < cast (add_months (cast (a.dt_nep_restructuration as date format 'YYYYMMDD'), 12) as integer) and a.DT_NPE_SORTIE is not null and a.DT_NPE_SORTIE <> '99991231' and a.dt_npe_restructuration is not null and a.dt_npe_restructuration <> '99991231'"
Debug.Print Join(ExtractFieldnames(s), vbNewLine)
End Sub
Results in VB Editor's immediate window
a.DT_NPE_SORTIE
a.dt_nep_restructuration
a.DT_NPE_SORTIE
a.DT_NPE_SORTIE
a.dt_npe_restructuration
a.dt_npe_restructuration
I need to find numbers from a string. How does one find numbers from a string in VBA Excel?
Assuming you mean you want the non-numbers stripped out, you should be able to use something like:
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
Calling this with:
Dim myStr as String
myStr = onlyDigits ("3d1fgd4g1dg5d9gdg")
MsgBox (myStr)
will give you a dialog box containing:
314159
and those first two lines show how you can store it into an arbitrary string variable, to do with as you wish.
Regular expressions are built to parse. While the syntax can take a while to pick up on this approach is very efficient, and is very flexible for handling more complex string extractions/replacements
Sub Tester()
MsgBox CleanString("3d1fgd4g1dg5d9gdg")
End Sub
Function CleanString(strIn As String) As String
Dim objRegex
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Global = True
.Pattern = "[^\d]+"
CleanString = .Replace(strIn, vbNullString)
End With
End Function
Expanding on brettdj's answer, in order to parse disjoint embedded digits into separate numbers:
Sub TestNumList()
Dim NumList As Variant 'Array
NumList = GetNums("34d1fgd43g1 dg5d999gdg2076")
Dim i As Integer
For i = LBound(NumList) To UBound(NumList)
MsgBox i + 1 & ": " & NumList(i)
Next i
End Sub
Function GetNums(ByVal strIn As String) As Variant 'Array of numeric strings
Dim RegExpObj As Object
Dim NumStr As String
Set RegExpObj = CreateObject("vbscript.regexp")
With RegExpObj
.Global = True
.Pattern = "[^\d]+"
NumStr = .Replace(strIn, " ")
End With
GetNums = Split(Trim(NumStr), " ")
End Function
Use the built-in VBA function Val, if the numbers are at the front end of the string:
Dim str as String
Dim lng as Long
str = "1 149 xyz"
lng = Val(str)
lng = 1149
Val Function, on MSDN
I was looking for the answer of the same question but for a while I found my own solution and I wanted to share it for other people who will need those codes in the future. Here is another solution without function.
Dim control As Boolean
Dim controlval As String
Dim resultval As String
Dim i as Integer
controlval = "A1B2C3D4"
For i = 1 To Len(controlval)
control = IsNumeric(Mid(controlval, i, 1))
If control = True Then resultval = resultval & Mid(controlval, i, 1)
Next i
resultval = 1234
This a variant of brettdj's & pstraton post.
This will return a true Value and not give you the #NUM! error. And \D is shorthand for anything but digits. The rest is much like the others only with this minor fix.
Function StripChar(Txt As String) As Variant
With CreateObject("VBScript.RegExp")
.Global = True
.Pattern = "\D"
StripChar = Val(.Replace(Txt, " "))
End With
End Function
This is based on another answer, but is just reformated:
Assuming you mean you want the non-numbers stripped out, you should be able to use something like:
'
' Skips all characters in the input string except digits
'
Function GetDigits(ByVal s As String) As String
Dim char As String
Dim i As Integer
GetDigits = ""
For i = 1 To Len(s)
char = Mid(s, i, 1)
If char >= "0" And char <= "9" Then
GetDigits = GetDigits + char
End If
Next i
End Function
Calling this with:
Dim myStr as String
myStr = GetDigits("3d1fgd4g1dg5d9gdg")
Call MsgBox(myStr)
will give you a dialog box containing:
314159
and those first two lines show how you can store it into an arbitrary string variable, to do with as you wish.
Alternative via Byte Array
If you assign a string to a Byte array you typically get the number equivalents of each character in pairs of the array elements. Use a loop for numeric check via the Like operator and return the joined array as string:
Function Nums(s$)
Dim by() As Byte, i&, ii&
by = s: ReDim tmp(UBound(by)) ' assign string to byte array; prepare temp array
For i = 0 To UBound(by) - 1 Step 2 ' check num value in byte array (0, 2, 4 ... n-1)
If Chr(by(i)) Like "#" Then tmp(ii) = Chr(by(i)): ii = ii + 1
Next i
Nums = Trim(Join(tmp, vbNullString)) ' return string with numbers only
End Function
Example call
Sub testByteApproach()
Dim s$: s = "a12bx99y /\:3,14159" ' [1] define original string
Debug.Print s & " => " & Nums(s) ' [2] display original string and result
End Sub
would display the original string and the result string in the immediate window:
a12bx99y /\:3,14159 => 1299314159
Based on #brettdj's answer using a VBScript regex ojbect with two modifications:
The function handles variants and returns a variant. That is, to take care of a null case; and
Uses explicit object creation, with a reference to the "Microsoft VBScript Regular Expressions 5.5" library
Function GetDigitsInVariant(inputVariant As Variant) As Variant
' Returns:
' Only the digits found in a varaint.
' Examples:
' GetDigitsInVariant(Null) => Null
' GetDigitsInVariant("") => ""
' GetDigitsInVariant(2021-/05-May/-18, Tue) => 20210518
' GetDigitsInVariant(2021-05-18) => 20210518
' Notes:
' If the inputVariant is null, null will be returned.
' If the inputVariant is "", "" will be returned.
' Usage:
' VBA IDE Menu > Tools > References ...
' > "Microsoft VBScript Regular Expressions 5.5" > [OK]
' With an explicit object reference to RegExp we can get intellisense
' and review the object heirarchy with the object browser
' (VBA IDE Menu > View > Object Browser).
Dim regex As VBScript_RegExp_55.RegExp
Set regex = New VBScript_RegExp_55.RegExp
Dim result As Variant
result = Null
If IsNull(inputVariant) Then
result = Null
Else
With regex
.Global = True
.Pattern = "[^\d]+"
result = .Replace(inputVariant, vbNullString)
End With
End If
GetDigitsInVariant = result
End Function
Testing:
Private Sub TestGetDigitsInVariant()
Dim dateVariants As Variant
dateVariants = Array(Null, "", "2021-/05-May/-18, Tue", _
"2021-05-18", "18/05/2021", "3434 ..,sdf,sfd 444")
Dim dateVariant As Variant
For Each dateVariant In dateVariants
Debug.Print dateVariant & ": ", , GetDigitsInVariant(dateVariant)
Next dateVariant
Debug.Print
End Sub
Public Function ExtractChars(strRef$) As String
'Extract characters from a string according to a range of charactors e.g'+.-1234567890'
Dim strA$, e%, strExt$, strCnd$: strExt = "": strCnd = "+.-1234567890"
For e = 1 To Len(strRef): strA = Mid(strRef, e, 1)
If InStr(1, strCnd, strA) > 0 Then strExt = strExt & strA
Next e: ExtractChars = strExt
End Function
In the immediate debug dialog:
? ExtractChars("a-5d31.78K")
-531.78
How can I split up AB2468123 with excel-vba
I tried something along these lines:
myStr = "AB2468123"
split(myStr, "1" OR "2" OR "3"......."9")
I want to get only alphabet (letters) only.
Thanks.
How about this to retrieve only letters from an input string:
Function GetLettersOnly(str As String) As String
Dim i As Long, letters As String, letter As String
letters = vbNullString
For i = 1 To Len(str)
letter = VBA.Mid$(str, i, 1)
If Asc(LCase(letter)) >= 97 And Asc(LCase(letter)) <= 122 Then
letters = letters + letter
End If
Next
GetLettersOnly = letters
End Function
Sub Test()
Debug.Print GetLettersOnly("abc123") // prints "abc"
Debug.Print GetLettersOnly("ABC123") // prints "ABC"
Debug.Print GetLettersOnly("123") // prints nothing
Debug.Print GetLettersOnly("abc123def") // prints "abcdef"
End Sub
Edit: for completeness (and Chris Neilsen) here is the Regex way:
Function GetLettersOnly(str As String) As String
Dim result As String, objRegEx As Object, match As Object
Set objRegEx = CreateObject("vbscript.regexp")
objRegEx.Pattern = "[a-zA-Z]+"
objRegEx.Global = True
objRegEx.IgnoreCase = True
If objRegEx.test(str) Then
Set match = objRegEx.Execute(str)
GetLettersOnly = match(0)
End If
End Function
Sub test()
Debug.Print GetLettersOnly("abc123") //prints "abc"
End Sub
Simpler single shot RegExp
Sub TestIt()
MsgBox CleanStr("AB2468123")
End Sub
Function CleanStr(strIn As String) As String
Dim objRegex As Object
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Pattern = "[^a-zA-Z]+"
.Global = True
CleanStr = .Replace(strIn, vbNullString)
End With
End Function
This is what i have found out that works the best. It may be somewhat basic, but it does the job :)
Function Split_String(Optional test As String = "ABC111111") As Variant
For i = 1 To Len(test)
letter = Mid(test, i, 1)
If IsNumeric(letter) = True Then
justletters = Left(test, i - 1)
justnumbers = Right(test, Len(test) - (i - 1))
Exit For
End If
Next
'MsgBox (justnumbers)
'MsgBox (justletters)
'just comment away the answer you want to have :)
'Split_String = justnumbers
'Split_String = justletters
End Function
Possibly the fastest way is to parse a Byte String:
Function alpha(txt As String) As String
Dim b, bytes() As Byte: bytes = txt
For Each b In bytes
If Chr(b) Like "[A-Za-z]" Then alpha = alpha & Chr(b)
Next b
End Function
More information here.
If I have a string: "foo, bar" baz, test, blah, how do I remove a specific comma, i.e. not all of them, but just one of my choosing?
with Replace and INSTR it looks like I have not know where the comma is. The problem is, I'll only want to remove the comma if it appears between quotation marks.
So, I may want to remove the first comma and I may not.
Put more clearly, if there is a comma between a set of quotation marks, I need to remove it. if not, then there's nothing to do. But, I can't just remove all the commas, as I need the others in the string.
Try with Regexp in this way:
Sub foo()
Dim TXT As String
TXT = """foo, bar"" baz, test, blah"
Debug.Print TXT
Dim objRegExp As Object
Set objRegExp = CreateObject("vbscript.regexp")
With objRegExp
.Global = True '
.Pattern = "(""\w+)(,)(\s)(\w+"")"
Debug.Print .Replace(TXT, "$1$3$4")
End With
End Sub
It works as expected for the sample value you have provided but could require additional adjustments by changing .Pattern for more complicated text.
EDIT If you want to use this solution as an Excel function than use this code:
Function RemoveCommaInQuotation(TXT As String)
Dim objRegExp As Object
Set objRegExp = CreateObject("vbscript.regexp")
With objRegExp
.Global = True
.Pattern = "(""\w+)(,)(\s)(\w+"")"
RemoveCommaInQuotation = .Replace(TXT, "$1$3$4")
End With
End Function
Ugh. Here's another way
Public Function foobar(yourStr As String) As String
Dim parts() As String
parts = Split(yourStr, Chr(34))
parts(1) = Replace(parts(1), ",", "")
foobar = Join(parts, Chr(34))
End Function
With some error-checking for odd number of double quotes:
Function myremove(mystr As String) As String
Dim sep As String
sep = """"
Dim strspl() As String
strspl = Split(mystr, sep, -1, vbBinaryCompare)
Dim imin As Integer, imax As Integer, nstr As Integer, istr As Integer
imin = LBound(strspl)
imax = UBound(strspl)
nstr = imax - imin
If ((nstr Mod 2) <> 0) Then
myremove = "Odd number of double quotes"
Exit Function
End If
For istr = imin + 1 To imax Step 2
strspl(istr) = Replace(strspl(istr), ",", "")
Next istr
myremove = Join(strspl(), """")
End Function
I need to find numbers from a string. How does one find numbers from a string in VBA Excel?
Assuming you mean you want the non-numbers stripped out, you should be able to use something like:
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
Calling this with:
Dim myStr as String
myStr = onlyDigits ("3d1fgd4g1dg5d9gdg")
MsgBox (myStr)
will give you a dialog box containing:
314159
and those first two lines show how you can store it into an arbitrary string variable, to do with as you wish.
Regular expressions are built to parse. While the syntax can take a while to pick up on this approach is very efficient, and is very flexible for handling more complex string extractions/replacements
Sub Tester()
MsgBox CleanString("3d1fgd4g1dg5d9gdg")
End Sub
Function CleanString(strIn As String) As String
Dim objRegex
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Global = True
.Pattern = "[^\d]+"
CleanString = .Replace(strIn, vbNullString)
End With
End Function
Expanding on brettdj's answer, in order to parse disjoint embedded digits into separate numbers:
Sub TestNumList()
Dim NumList As Variant 'Array
NumList = GetNums("34d1fgd43g1 dg5d999gdg2076")
Dim i As Integer
For i = LBound(NumList) To UBound(NumList)
MsgBox i + 1 & ": " & NumList(i)
Next i
End Sub
Function GetNums(ByVal strIn As String) As Variant 'Array of numeric strings
Dim RegExpObj As Object
Dim NumStr As String
Set RegExpObj = CreateObject("vbscript.regexp")
With RegExpObj
.Global = True
.Pattern = "[^\d]+"
NumStr = .Replace(strIn, " ")
End With
GetNums = Split(Trim(NumStr), " ")
End Function
Use the built-in VBA function Val, if the numbers are at the front end of the string:
Dim str as String
Dim lng as Long
str = "1 149 xyz"
lng = Val(str)
lng = 1149
Val Function, on MSDN
I was looking for the answer of the same question but for a while I found my own solution and I wanted to share it for other people who will need those codes in the future. Here is another solution without function.
Dim control As Boolean
Dim controlval As String
Dim resultval As String
Dim i as Integer
controlval = "A1B2C3D4"
For i = 1 To Len(controlval)
control = IsNumeric(Mid(controlval, i, 1))
If control = True Then resultval = resultval & Mid(controlval, i, 1)
Next i
resultval = 1234
This a variant of brettdj's & pstraton post.
This will return a true Value and not give you the #NUM! error. And \D is shorthand for anything but digits. The rest is much like the others only with this minor fix.
Function StripChar(Txt As String) As Variant
With CreateObject("VBScript.RegExp")
.Global = True
.Pattern = "\D"
StripChar = Val(.Replace(Txt, " "))
End With
End Function
This is based on another answer, but is just reformated:
Assuming you mean you want the non-numbers stripped out, you should be able to use something like:
'
' Skips all characters in the input string except digits
'
Function GetDigits(ByVal s As String) As String
Dim char As String
Dim i As Integer
GetDigits = ""
For i = 1 To Len(s)
char = Mid(s, i, 1)
If char >= "0" And char <= "9" Then
GetDigits = GetDigits + char
End If
Next i
End Function
Calling this with:
Dim myStr as String
myStr = GetDigits("3d1fgd4g1dg5d9gdg")
Call MsgBox(myStr)
will give you a dialog box containing:
314159
and those first two lines show how you can store it into an arbitrary string variable, to do with as you wish.
Alternative via Byte Array
If you assign a string to a Byte array you typically get the number equivalents of each character in pairs of the array elements. Use a loop for numeric check via the Like operator and return the joined array as string:
Function Nums(s$)
Dim by() As Byte, i&, ii&
by = s: ReDim tmp(UBound(by)) ' assign string to byte array; prepare temp array
For i = 0 To UBound(by) - 1 Step 2 ' check num value in byte array (0, 2, 4 ... n-1)
If Chr(by(i)) Like "#" Then tmp(ii) = Chr(by(i)): ii = ii + 1
Next i
Nums = Trim(Join(tmp, vbNullString)) ' return string with numbers only
End Function
Example call
Sub testByteApproach()
Dim s$: s = "a12bx99y /\:3,14159" ' [1] define original string
Debug.Print s & " => " & Nums(s) ' [2] display original string and result
End Sub
would display the original string and the result string in the immediate window:
a12bx99y /\:3,14159 => 1299314159
Based on #brettdj's answer using a VBScript regex ojbect with two modifications:
The function handles variants and returns a variant. That is, to take care of a null case; and
Uses explicit object creation, with a reference to the "Microsoft VBScript Regular Expressions 5.5" library
Function GetDigitsInVariant(inputVariant As Variant) As Variant
' Returns:
' Only the digits found in a varaint.
' Examples:
' GetDigitsInVariant(Null) => Null
' GetDigitsInVariant("") => ""
' GetDigitsInVariant(2021-/05-May/-18, Tue) => 20210518
' GetDigitsInVariant(2021-05-18) => 20210518
' Notes:
' If the inputVariant is null, null will be returned.
' If the inputVariant is "", "" will be returned.
' Usage:
' VBA IDE Menu > Tools > References ...
' > "Microsoft VBScript Regular Expressions 5.5" > [OK]
' With an explicit object reference to RegExp we can get intellisense
' and review the object heirarchy with the object browser
' (VBA IDE Menu > View > Object Browser).
Dim regex As VBScript_RegExp_55.RegExp
Set regex = New VBScript_RegExp_55.RegExp
Dim result As Variant
result = Null
If IsNull(inputVariant) Then
result = Null
Else
With regex
.Global = True
.Pattern = "[^\d]+"
result = .Replace(inputVariant, vbNullString)
End With
End If
GetDigitsInVariant = result
End Function
Testing:
Private Sub TestGetDigitsInVariant()
Dim dateVariants As Variant
dateVariants = Array(Null, "", "2021-/05-May/-18, Tue", _
"2021-05-18", "18/05/2021", "3434 ..,sdf,sfd 444")
Dim dateVariant As Variant
For Each dateVariant In dateVariants
Debug.Print dateVariant & ": ", , GetDigitsInVariant(dateVariant)
Next dateVariant
Debug.Print
End Sub
Public Function ExtractChars(strRef$) As String
'Extract characters from a string according to a range of charactors e.g'+.-1234567890'
Dim strA$, e%, strExt$, strCnd$: strExt = "": strCnd = "+.-1234567890"
For e = 1 To Len(strRef): strA = Mid(strRef, e, 1)
If InStr(1, strCnd, strA) > 0 Then strExt = strExt & strA
Next e: ExtractChars = strExt
End Function
In the immediate debug dialog:
? ExtractChars("a-5d31.78K")
-531.78