I am currently using VBA script to transfer a CSV table to Access (from inside Excel)
objAccess.DoCmd.TransferText acImportDelim, "", _
"table1", "C:\donPablo\StackOverFlow\StackCSV.csv", True
The problem is that Access incorrectly defines Types for my columns.
Some of my columns have text and numbers rows, that's why half of the imports are damaged with an error code: "Type Conversion Failure"
I have read on the internet that you can fix that by
Creating the table with the exact same name and with predefined types for columns
objAccess.DoCmd.RunSQL "CREATE TABLE " + cstrTable + "(id Text);"
That didn't work. The same error.
Adding first column of type Text into the CSV file
So I added a row which is 100% text. The same error.
It seems like there is some kind of "clever" conversion going on inside Access and I can't bypass it.
The only possible scenario to bypass this conversion would be to convert all entries inside CSV file using this logic:
Before:
value1,value2,"value3", value4
After
"value1","value2","value3", "value4"
Is there a way to do this operation? regex of some kind maybe?
I created a hardcode solution for the above mentioned problem (no regex)
Dim current_Char As Variant
ignoretext = False
For Counter = 1 To Len(currentLine)
current_Char = Mid(currentLine, Counter, 1)
next_Char = Mid(currentLine, Counter + 1, 1)
If ignoretext = False And current_Char = """" Then 'opening of existing quote
ignoretext = True
newLine = newLine & current_Char
ElseIf ignoretext = True And current_Char = """" Then 'ending of existing quote
ignoretext = False
newLine = newLine & current_Char
ElseIf ignoretext = True Then
newLine = newLine & current_Char
ElseIf ignoretext = False Then
If current_Char = "," Then
If last_Char <> """" Then
newLine = newLine & """"
End If
newLine = newLine & current_Char
If next_Char <> """" Then
newLine = newLine & """"
End If
Else
newLine = newLine & current_Char
End If
Else
newLine = newLine & current_Char
End If
last_Char = current_Char
Next
If Mid(currentLine, 1, 1) <> """" Then
newLine = """" & newLine
End If
If Mid(currentLine, Len(currentLine), 1) <> """" Then
newLine = newLine & """"
End If
Some of the variable definitions probably missing but the logic is still there ;)
what is does basically:
before
"fsdf, dfafs",val,",fsd",156,fsd
after
"fsdf, dfafs","val",",fsd","156","fsd"
all of your fields are now Text type ;)
logic ignores all the commas once existing quote is detected
it will continue to ignore unless ending quote is found
for all other commas logic will add a before_quote if previous Char was not a quote
for all other commas logic will add a after_quote if next Char will not be a quote
all other chars will be appended to string AS IS
finally, at the end of the logic we will add quote at Start or End of string depending on existence of existing quotes at mentioned positions
have fun
Related
I am using following code to read csv file and finally the data is converted into array.
Function Sample(strPath) As String()
Dim MyData As String, strData() As String
Open strPath For Binary As #1
MyData = Space$(LOF(1))
Get #1, , MyData
Close #1
Sample = Split(MyData, vbCrLf)
End Function
Following code convert each comma separated line into array.
SaleRows = Sample(filepath)
For Each SaleRow In SaleRows
SaleRowArray = Split(SaleRow, ",")
Next SaleRow
Everything works fine but when a cell contains comma, my above function fails. Is there any way to handle comma in a particular cell?
Sample csv
Please observe comma in second row.
When I get array from the comma record, I get below.
It's likely that the strings in your CSV file are escaped with quote marks. If you want to parse the CSV using your own code, then your code needs to be able to ignore commas which occur inside quotes.
A quick way to do this would be to use RegEx. You could try the following:
Private Function changeDelimiter(line as String) as String
Dim regEx As Object
Set regEx = CreateObject("VBScript.regexp")
regEx.IgnoreCase = True
regEx.Global = True
regex.Pattern = ",(?=([^" & Chr(34) & "]*" & Chr(34) & "[^" & Chr(34) & "]*" & Chr(34) & ")*(?![^" & Chr(34) & "]*" & Chr(34) & "))"
changeDelimiter = regex.Replace(line, "#|#")
End Function
Then change the Split() line in your code as follows:
SaleRowArray = Split(changeDelimiter(SaleRow), "#|#")
The function replaces all commas outside quote marks with #|# (which I assume won't ever come up in your input data). You then split the lines into data fields on #|# instead of comma.
I have a query that I execute through VBA in Access 2010. The result of the query should be AFR, but it returns AFR with an extra line below it. I have added the "'" character to make the extra line visible.
TempHold = rs.GetString
Debug.Print "'" & TempHold & "'"
Returns this:
'AFR
'
But should return this:
'AFR'
I have tried using the below code, but none of the If statements evaluate as True. The code should check for a " ", a vbNewLine, or vbCrLf character but none evaluate as true. Does anyone know of any additional characters that would result in a new line?
If Right(TempHold, 1) = " " Then
TempHold = Left(TempHold, Len(TempHold) - 1)
ElseIf Right(TempHold, 2) = vbNewLine Or Right(TempHold, 2) = vbCrLf Then
TempHold = Left(TempHold, Len(TempHold) - 2)
End If
Use:
Asc(Right(TempHold, 1))
to get the Ascii character code.
Once you've found the character code (which, as you wrote in your comment, was 13), you can use your code to remove it:
If Right(TempHold, 1) = Chr(13) Then
TempHold = Left(TempHold, Len(TempHold) - 1)
End If
In this case, you can also use vbCr, which is the same as Chr(13).
The best way to get rid of the carriage return in my opinion is to stop it being created in the first place. This method is a lot tidier than having to remove the last character.
In the .GetString method there is a parameter for RowDelimiter which by default is set to be a carriage return. However you can change this to be whatever you want including a zero length string as follows:
rs.GetString(, , , "")
If you run your debug again with this code:
rs.GetString(, , , "")
Debug.Print "'" & TempHold & "'"
You will get this result:
'AFR'
Remember if you want something different to be placed between rows then just change the zero length string to whatever you need.
Issue, where the character I am removing does not exist I get a blank string
Aim: To look for three characters in order and only get the characters to the left of the character I am looking for. However if the character does not exist then to do nothing.
Code:
Dim vleftString As String = File.Name
vleftString = Left(vleftString, InStr(vleftString, "-"))
vleftString = Left(vleftString, InStr(vleftString, "_"))
vleftString = Left(vleftString, InStr(vleftString, " "))
As a 'fix' I have done
Dim vleftString As String = File.Name
vleftString = Replace(vleftString, "-", " ")
vleftString = Replace(vleftString, "_", " ")
vleftString = Left(vleftString, InStr(vleftString, " "))
vleftString = Trim(vleftString)
Based on Left of a character in a string in vb.net
If File.Name is say 1_2.pdf it passes "-" and then works on line removing anything before "" (though not "" though I want it to)
When it hits the line for looking for anything left of space it then makes vleftString blank.
Since i'm not familiar (and avoid) the old VB functions here a .NET approach. I assume you want to remove the parts behind the separators "-", "_" and " ", then you can use this loop:
Dim fileName = "1_2.pdf".Trim() ' Trim used to show you the method, here nonsense
Dim name = Path.GetFileNameWithoutExtension(fileName).Trim()
For Each separator In {"-", "_", " "}
Dim index = name.IndexOf(separator)
If index >= 0 Then
name = name.Substring(0, index)
End If
Next
fileName = String.Format("{0}{1}", name, Path.GetExtension(fileName))
Result: "1.pdf"
Oh my god i hate this thing, i tried millions of ways but couldn't find a working one. Let me explain:
I'm testing each line and checking the first word to be "copy" alright ? After the word copy i want to see if the next word is "1" , the third is "<" and the last is ">" , if all these conditions are fullfilled then the text between "<" and ">" needs to be stored in the variable "copy1" (even if there is more than 1 word between them).
What my code is:
For i = 0 To lstCode.Items.Count - 1
Dim str As String = lstCode.Items.Item(i)
Dim strA() As String = Split(str)
Dim copy1 as string
Dim copy2 as string
Select Case strA(0)
Case copy
If strA(1) = "1" And strA(2) = "<" And strA(strA.Count - 1) = ">" Then
copy1 = ""
For lr As Integer = 3 To strA.Count - 2
copy1 &= (strA(lr) & " ")
Next
End if
End select
And, when i debug it i get the error: Index was outside the bounds of the array ... Does anybody have any idea ?
There is something important i forgot to add, this is the whole code:
Case "copy"
If strA(1) = "1" And strA(2) = "<" And strA(strA.Count - 1) = ">" Then
copy1 = ""
For lr As Integer = 3 To strA.Count - 2
copy1 &= (strA(lr) & " ")
Next
ElseIf strA(1) = "2" And strA(2) = "<" And strA(strA.Count - 1) = ">" Then
copy2 = ""
For lrs As Integer = 3 To strA.Count - 2
copy2 &= (strA(lrs) & " ")
Next
ElseIf strA(1) = "run" Then
Try
IO.File.Copy(copy1, copy2)
Catch ex As IO.IOException
End Try
End If
End Select
So everything works like a charm: copy 1 < c:\csb.log > , copy 2 < c:\blabla.txt > but when the " copy run " statement comes in it gives me the error...
You need to change the operator And with AndAlso.
The second one applies Short Circuit Evaluation to your expression, meaning if the first expression is false the second, third and so on expressions on the same line are not evaluated.
In your line
If strA(1) = "1" And strA(2) = "<" And .......
when the value is "Run" you still evaluate the expression strA(2) = "<" but there is no element at index 2 so you get the error.
This is my code:
With ad.Tables(2)
For i As Integer = 0 To .Rows.Count - 1
If .Rows(i)("name") & "" <> "" Then
temp &= .Rows(i)("name") & ", "
End If
Next
End With
temp = temp.Trim(",")
testing &= "&Name=" & temp & vbCrLf
With this is get a comma in the end of the string. But if I do
temp = temp.Trim.Trim(",")
all commas are deleted.
How do I keep all commas and only delete the last one?
temp = temp.TrimEnd(CChar(","))
That will do it and I think it is the easiest way.
temp = temp.Trim().Substring(0, temp.Length - 1)
or
temp = temp.Trim().Remove(temp.Length - 1)
You can avoid the Trim/extra character if you set a delimiter within the loop
Dim delimiter as string = ""
For i As Integer = 0 To .Rows.Count - 1
If .Rows(i)("name") & "" <> "" Then
temp &= delimiter & .Rows(i)("name")
delimiter = ","
End If
Next
The Trim() function has a Char() (static array of characters) parameter on it, you don't need to pass a Char explicitly.
' VB.Net Version
", Hello ^_^ ^_^ ,,, , ,, ,, ,".Trim({" "c, ","c})
//C# version
", Hello ^_^ ^_^ ,,, , ,, ,, ,".Trim({' ', ','})
Would produce the output
"Hello ^_^ ^_^"
The multi-parameter .Trim() removes the specified characters from both the beginning and the end of the string. If you want to only trim out the beginning or the end, use .TrimStart() or .TrimEnd() respectively.
This works:
dim AlarmStr as string="aaa , bbb , ccc , "
AlarmStr = AlarmStr.Remove(AlarmStr.LastIndexOf(","))
Check to see if the loop is done before adding the last comma. #cleaner
While dr.Read
For c As Integer = 0 To dr.FieldCount - 1
s.Append(dr(c).ToString.Trim)
'This line checks if the loop is ending before adding a comma
If (c < dr.FieldCount - 1) Then s.Append(",")
Next
s.Append(vbCrLf)
End While
I wonder, that based on the OP's code sample, nobody suggested to use String.Join or build an output with StringBuilder
Dim names As New List(Of String)
With ad.Tables(2)
For i As Integer = 0 To .Rows.Count - 1
' DataRow("columnName").ToString() returns value or empty string if value is DbNull
If .Rows(i)("name").ToString() <> "" Then
names.Add(.Rows(i)("name"))
End If
Next
End With
Dim temp As String = String.Join(", ", names)
testing &= "&Name=" & temp & vbCrLf
With LINQ and DataRow extension method .Field(Of T) code will look simpler
Dim names = ad.Tables(2).
AsEnumerable().
Select(row => row.Field<String>("name")).
Where(name => String.IsNullOrEmpty(name) = False)
Dim temp As String = String.Join(", ", names)
testing &= "&Name=" & temp & vbCrLf
If you go further you can(should) use StringBuilder for building a string and use Aggregate method to build string from the collection
I know that a little bit odd, but I found this works for me:
Visual Basic:
Every time: mystring = "today, I love go out , , , ," (less than five commas and spaces)
mystring.Trim.TrimEnd(",").Trim.TrimEnd(",").Trim.TrimEnd(",").Trim.TrimEnd(",").Trim.TrimEnd(",")
temp = temp.TrimEnd()
this trims the trailing spaces from a string.