I have a problem when I try to convert my Array into a comma-separated String. In the example below, I retrieve all the files in my email and send them to my server to add them. My server sends me back an ID that is stored in the Array. Then I try to convert this Array into a String.
Dim filesId(1 To 100) As String
Dim tmpString As String
Dim count As Integer
count = 0
Set db = Session.Currentdatabase
Set CurrentDocColl = db.Unprocesseddocuments
Set doc = CurrentDocColl.Getfirstdocument
While Not doc Is Nothing
Set item = doc.GETFIRSTITEM("Body")
If doc.HasEmbedded Then
ForAll attachment In item.EmbeddedObjects
jsonBody="value={""filename"":"""+attachment.Name+"""}"
Set http=session.CreateHTTPRequest()
http.preferstrings = True
Call http.SetHeaderField("ContentType","application/json")
ret = http.Post(url, jsonBody)
If IsNumeric(ret) Then
count = count + 1
filesId(count) = ret
Else
MessageBox ret
End If
End ForAll
End If
Set doc=CurrentDocColl.Getnextdocument(doc)
Wend
ForAll itemValue In filesId
If CStr(itemValue ) <> "" Then
If tmpString = "" Then
tmpString = itemValue
Else
tmpString = tmpString & "," & itemValue
End If
End If
End ForAll
MessageBox tmpString
The problem is that the final String contains only the first value of the array and not the next values.
Example with this Array: [3567,3568,3569,3570]
Desired result String: 3567,3568,3569,3570
Result received: 3567
I don't understand where this problem comes from, especially since it also doesn't work with the Join() and Implode() functions.
EDIT
Indeed after having looked in the debugger, we can see that my data are present in the Array but in a particular format because the quotes of the strings do not close. What can I do to fix this?
Thank you very much for your help
Your http post result contains line break at its end. That is why the string looks so "strange" in debugger. This resuls in the following tmpString:
"3267
,3268
,3269
,3270"
Messagebox is not able to show all line breaks... so it only shows the string until the first line break.
You need to remove line breaks from your string before concatenating:
Dim badChars(2) as String
Dim goodChars(2) as String
badChars(0) = Chr$(0)
badChars(1) = Chr$(10)
badChars(2) = Chr$(13)
...
filesId(count) = Replace( ret, badChars, goodChars )
As I do not know WHICH line break / carriage return is there in your string I replace the three most common ones with blank in above code... Might be another unprintable character in there that you have to get rid of, then you need to examine Right( ret , 1) and check, what is in there and replace that.
I don't see a dim statement for tmpString. If there is no dim, then it is a variant. If it is a variant, then your assignment tmpString = item is dynamically defining tmpString as a numeric type. That would cause your assignment tmpString = tmpString & "," & item to fail. Since you appear to be expecting numeric data for ret, and you are assigning that into the filesId array, and item is a value from filesId, you need to be using CStr(item) in both of your assignments.
Related
I have a column which contain cells that have some list of alphanumeric number system as follows:
4A(4,5,6,7,8,9); 4B(4,5,7,8); 3A(1,2,3); 3B(1,2,3), 3C(1,2)
On a cell next to it, I use a UDF function to get rid of special characters "(),;" in order to leave the data as
4A456789 4B4578 3A123 3B123 3C12
Function RemoveSpecial(Str As String) As String
Dim SpecialChars As String
Dim i As Long
SpecialChars = "(),;-abcdefghijklmnopqrstuvwxyz"
For i = 1 To Len(SpecialChars)
Str = Replace$(Str, Mid$(SpecialChars, i, 1), "")
Next
RemoveSpecial = Str
End Function
For the most part this works well. However, on certain occasions, the cell would contain an unorthodox pattern such as when a space is included between the 4A and the parenthesized items:
4A (4,5,6,7,8,9);
or when a text appears inside the parenthesis (including two spaces on each side):
4A (4,5, skip 8,9);
or a space appears between the first two characters:
4 A(4,5,6)
How would you fix this so that the random spaces are removed except to delaminate the actual combination of data?
One strategy would be to substitute the patterns you want to keep before eliminating the "special" characters, then restore the desired patterns.
From your sample data, it look like you want to keep a space only if it follow ); or ),
Something like this:
Function RemoveSpecial(Data As Variant) As Variant
Dim SpecialChars As String
Dim KeepStr As Variant, PlaceHolder As Variant, ReplaceStr As Variant
Dim i As Long
Dim DataStr As String
SpecialChars = " (),;-abcdefghijklmnopqrstuvwxyz"
KeepStr = Array("); ", "), ")
PlaceHolder = Array("~0~", "~1~") ' choose a PlaceHolder that won't appear in the data
ReplaceStr = Array(" ", " ")
DataStr = Data
For i = LBound(KeepStr) To UBound(KeepStr)
DataStr = Replace$(DataStr, KeepStr(i), PlaceHolder(i))
Next
For i = 1 To Len(SpecialChars)
DataStr = Replace$(DataStr, Mid$(SpecialChars, i, 1), vbNullString)
Next
For i = LBound(KeepStr) To UBound(KeepStr)
DataStr = Replace$(DataStr, PlaceHolder(i), ReplaceStr(i))
Next
RemoveSpecial = Application.Trim(DataStr)
End Function
Another strategy would be regular expressions (RegEx)
It looks like a regular expression could come in handy here, for example:
Function RemoveSpecial(Str As String) As String
With CreateObject("vbscript.regexp")
.Global = True
.Pattern = "\)[;,]( )|[^A-Z\d]+"
RemoveSpecial = .Replace(Str, "$1")
End With
End Function
I have used the regular expression:
\)[;,]( )|[^A-Z\d]+
You can see an online demo to see the result in your browser. The way this works is to apply a form of what some would call "The best regex trick ever!"
\)[;,]( ) - Escape a closing paranthesis, then match either a comma or semicolon before we capture a space character in our 1st capture group.
| - Or use the following alternation:
[^A-Z\d]+ - Any 1+ char any other than in given character class.
EDIT:
In case you have values like 4A; or 4A, you can use:
(?:([A-Z])|\))[;,]( )|[^A-Z\d]+
And replace with $1$2. See an online demo.
I have a column where i pickup increasing numbering values, and their format is xx_yy
so the first is 1_0, second 1_1 and so forth, no we are at 23_31
I want to get the right side of the string, and i am already getting the left side correctly.
using
newActionId = Left(lastActionID, (Application.WorksheetFunction.Find("_", lastActionID, 1) - 1))
i wish to do the following, human writing below
nextSubid = entire stringvalue AFTER special character "_"
I tried just switching left to right, didnt go so well, do you have a suggestion?
You can use Split function to get the relevant text.
Syntax: Split(expression, [ delimiter, [ limit, [ compare ]]])
Option Explicit
Sub Sample()
Dim id As String
Dim beforeSplChr As String
Dim afterSplChr As String
id = "23_31"
beforeSplChr = Split(id, "_")(0)
afterSplChr = Split(id, "_")(1)
Debug.Print beforeSplChr
Debug.Print afterSplChr
End Sub
Another way
Debug.Print Left(id, (InStrRev(id, "_", -1) - 1)) '<~~ Left Part
Debug.Print Right(id, (InStrRev(id, "_", -1) - 1)) '<~~ Right Part
Even though Siddharth Rout has given what can probably be considered a better answer here, I felt that this was worth adding:
To get the second part of the string using your original method, you would want to use the Mid function in place of Left, rather than trying to use Right.
Mid(string, start, [ length ])
Returns length characters from string, starting at the start position
If length is omitted, then will return characters from the start position until the end of the string
newActionId = Mid(lastActionID, Application.WorksheetFunction.Find("_", lastActionID, 1) + 1)
Just for fun (Split is the way to go here), an alternative way using regular expressions:
Sub Test()
Dim str As String: str = "23_31"
With CreateObject("VBScript.RegExp")
.Global = True
.Pattern = "\d+"
Debug.Print .Execute(str)(0) 'Left Part
Debug.Print .Execute(str)(1) 'Right Part
End With
End Sub
Btw, as per my comment, your first value could also be achieved through:
Debug.Print Val(str)
Split function of string is very usefull for this type of query.
Like:
String s = "23_34";
String left = s.split("_")[0];
String right = s.split("_")[1];
Or you can also use combination of indexOf and substring method together.
String left = s.substring(0,s.indexOf('_')+1)
String right = s.substring(s.indexOf('_'));
im having a hard time getting a function working. I need to search message.text for each "," found, for each "," found I need to get the number position of where the "," is located in the string. For example: 23232,111,02020332,12 it would return 6/10/19 where the "," are located (index of). My code finds the first index of the first , but then just repeats 6 6 6 6 over, any help would be appreciated thanks.
Heres my code:
For Each i As Char In message.Text
If message.Text.Contains(",") Then
Dim data As String = message.Text
Dim index As Integer = System.Text.RegularExpressions.Regex.Match(data, ",").Index
commas.AppendText(index & " ")
End If
Next
You can try it this way; instantiate a Regex object and increment each time the position from which you start the matching (this possibility is not available with the static method Match).
Dim reg As New System.Text.RegularExpressions.Regex(",")
Dim Index As Integer = reg.Match(data).Index
Do While Index > 0
commas.AppendText(index & " ")
Index = reg.Match(data, Index + 1).Index
Loop
p.s the returned indices are zero-based.
Just use the Regex.Matches method
Dim message As String = "23232,111,02020332,12"
Dim result As String = ""
For Each m As Match In Regex.Matches(message, ",")
result &= m.Index + 1 & " "
Next
I should also add that indexes are 0 based (which is why +1 is added to m.Index). If you later need these values to point to the position of a particular comma, you may be off by 1 and could potentially try to access an index larger than the actual string.
I am trying to analyze a String with VBA code.
I read a String that looks like that :
myStringInput = "FRAG_INST = someValue,DR = otherValue, FRAG = anotherValue"
And in my code I would like to associate some variable according to the value read in the string, I would like to initialize my variables like that :
Dim dr, frag, fraginst As String
fraginst = someValue
dr = otherValue
frag = anotherValue
I have tried things like Trim/Split/InStr combination but I always ended up with wrong values.
I cannot just use "Mid" function because length of the values mays change from one execution to another...
To be clearer, I need to design function like this
fraginst = NiceFunction("FRAG_INST",myStringInput)
and it would return "someValue"
Is there an easy way to do what I want ?
Thanks
This solution is working fine. May be you can try this. I have not used any Regular expressions though.
Approach:
I first splitted the string by delimiter ,(comma). Traversed through each of the array elements and splitted each element by '='. Compared the value to the string present on the left side of '=' and returned value to the right of '=' after trimming. Mid function was needed.
myStringInput = "FRAG_INST = someValue,DR = otherValue, FRAG = anotherValue"
fraginst = NiceFunction("FRAG_INST",myStringInput)
MsgBox fraginst
Function NiceFunction(str1, str2)
tempArr1 = Split(str2,",")
For i=0 To UBound(tempArr1)
tempArr2 = Split(tempArr1(i),"=")
If StrComp(Trim(tempArr2(0)),str1,1)=0 Then
NiceFunction = Trim(tempArr2(1))
Exit For
End If
Next
End Function
Function NiceFunction( varName, inputString )
Dim match
With CreateObject("VBScript.RegExp")
.IgnoreCase = True
.Global = False
.Pattern = "(?:^|,)\s*" & varName & "\s*=\s*([^,]*)"
For Each match in .Execute( inputString )
NiceFunction = match.subMatches.Item(0)
Next
End With
End Function
You can use a RegExp object to extract the part of the string you need.
Instead of insisting on 'single' variables (DR, ...) which would need the dynamic creation of variables at run-time, you should use a dictionary:
Option Explicit
Function s2d(s)
If IsEmpty(gR) Then
Set gR = New RegExp
gR.Global = True
gR.Pattern = "(\w+)\s?=\s?(\w+)"
End If
Set s2d = CreateObject("Scripting.Dictionary")
Dim m
For Each m In gR.Execute(s)
If s2d.Exists(m.SubMatches(0)) Then
' Error: dup key
Else
s2d.Add m.SubMatches(0), m.SubMatches(1)
End If
Next
End Function
Function qq(s)
qq = """" & s & """"
End Function
Dim gR ' "static" in s2d()
Dim s : s = "FRAG_INST = someValue,DR = otherValue, FRAG = anotherValue"
If 0 < WScript.Arguments.Count Then s = WScript.Arguments(0)
Dim d : Set d = s2d(s)
Dim k
For Each k In d.Keys()
WScript.Echo qq(k), "=>", qq(d(k))
Next
If d.Exists("DR") Then WScript.Echo "DR:", d("DR") ' access 'single' var
Output:
cscript 44282497.vbs
"FRAG_INST" => "someValue"
"DR" => "otherValue"
"FRAG" => "anotherValue"
DR: otherValue
P.S.
I used a RegExp, because variable names must be 'words'/match "\w+" and your sample data values dito, whereas the separators look like a mess/use spaces creatively. See here fore how to use RegExps in VBA.
I have an array with some words that i want to replace with other words, in fact, i have some problem:
Eg:
Var1 -> wksArray
Var2 -> wksArrayBigger
string : Dim wksArray, wksArrayBigger as Variant
When i try to replace wksArray with "test1", it will cause:
var1 -> teste1
var2 -> test1Bigger
string : Dim teste1, teste1Bigger as Variant
How can i solve that?
Function FindAndReplace(VBProjToClean, varArray)
Dim i, b As Integer
Dim str, replace_str As String
Dim VBC As VBComponent
For Each VBC In VBProjToClean.VBComponents
i = 1
With VBC.CodeModule
Do Until i > .CountOfLines
If Not .ProcOfLine(i, vbext_pk_Proc) = "VBE_Remove_Comments" Then
str = .Lines(i, 1)
End If
For b = 1 To UBound(varArray)
If InStr(1, str, varArray(b), vbTextCompare) > 0 Then
replace_str = Replace(str, varArray(b), varArray(b) & "banana")
.ReplaceLine i, replace_str
str = .Lines(i, 1)
End If
Next b
i = i + 1
Loop
End With
Next
End Function
While not a proper fix to your problem, you could sort your search list and possibly add some intermediary replacements should there be conflicts you cant resolve.
arrReplaceBigger -> arIM01
arrReplace -> aR
arIM01 -> aRB '
If your just replacing variable names, you could create a function to replace Replace that would do a number of extra replacements, appending however many possibilities for the next character there are.
white-space, comma, period, left bracket, right bracket, new line, plus, ...., etc
Or instead of doing many extra replacements you could do the same thing using Regular Expressions as David suggests.
Write a function to find out if something is a valid character for a VBA variable
Then for each pear of strings,
Look for the occurences of the string to be replaced, verify that preceding and succeding positoins do not contain valid characters, and if so, replace the string.