VBA text to columns with "" delimiters - vba

I will be quick.
I have a variable 'strLine' with text:
The exact string will look like that:
"Text1","Text2","Text3","Text4","Text5"
So, delimiter in my case is: "
How I can extract text and write it in columns.
Expecting results in cells:
A1=Text1
B1=Text2
C1=Text3
D1=Text4
E1=Text5
Thanks

Use Split function, it'll return a 0-based array (ergo +1 in cells) :
Sub test_Andy()
Dim StrLine As String
Dim Str() As String
StrLine = Range("A2").Value 'If your value is in A2
'If you input the value manually, not really practical with so much "
StrLine = Chr(34) & "Text1" & Chr(34) & "," & Chr(34) & "Text2" & Chr(34) & "," & Chr(34) & "Text3" & Chr(34) & "," & Chr(34) & "Text4" & Chr(34) & "," & Chr(34) & "Text5" & Chr(34)
Debug.Print StrLine '"Text1","Text2","Text3","Text4","Text5"
Str = Split(StrLine, ",")
Dim i As Integer
For i = LBound(Str) To UBound(Str)
Cells(1, i + 1) = Str(i)
Cells(2, i + 1) = Replace(Str(i), Chr(34), vbNullString)
Next i
End Sub

You can use Split to split the text into an array, then remove the " from the start and the end of the parts using Mid :
strText = """Text1"",""Text2"",""Text3"",""Text4"",""Text5"""
aSplit = Split(strText, ",")
For Each strCurrent in aSplit
MsgBox Mid(strCurrent, 2, Len(strCurrent) - 2)
Next
Remark : You might want to add some checks to ensure that there is a " at the start and end before removing them.

edited to simulate a StrLine loop:
Dim iRow As Long
irow = 1
For Each StrLine In StrLines '<--' assuming a loop through many StrLines
Str = Split(Replace(StrLine, """", ""), ",")
Cells(iRow, 1).Resize(, UBound(Str) - LBound(Str)).Value = Str
iRow = iRow + 1
Next

Related

VBA Replace last field in ALL rows within csv around double quotes?

On Error Resume Next
Set FileSysObj = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1 ' Declare constant for reading for more clarity
Dim cntFile, strCSVFullFile, strCSVFile, strDIR, cntBadLines, cntAllLines, strArchiveDir, strSafeTime,strSafeDate
' -------------------------------------------------------------------------------------------
' Specify CSV file name from the input argument
strCSVFile = Wscript.Arguments(1) ' Transactions
strDIR = Wscript.Arguments(2) & "\" ' C:\Temp
strArchiveDir = Wscript.Arguments(3) & "\"
strSafeTime = Right("0" & Hour(Now), 2) & Right("0" & Minute(Now), 2) & Right("0" & Second(Now), 2)
strSafeDate = Year(Date) & Month(Date) & day(Date)
set folder = FileSysObj.getFolder(strDIR)
cntFile = 0
cntBadLines = 0
cntAllLines = 0
for each file in folder.Files
' check if the file is there and echo it.
if InStr(1,file.name,strCSVFile,1) <> 0 then
strCSVFullFile = file.name
cntFile = cntFile + 1
end if
next
if cntFile > 1 or cntFile = 0 then
' error and end
Wscript.Echo "Error - only 1 file required for this process. There are " & cntFile & " file(s) in the directory"
WScript.Quit
end if
wscript.echo "Checking the file " & strCSVFullFile & " in " & strDIR
NoOfCols = Wscript.Arguments(0) ' usually 8
strTemp = "temp.csv"
strmissing = "missingdata.csv"
Set objOutFile = FileSysObj.CreateTextFile(strDIR & strTemp,True)
Set objOutFileM = FileSysObj.CreateTextFile(strDIR & strmissing,True)
Set inputFile = FileSysObj.OpenTextFile(strDIR & strCSVFullFile, ForReading, True)
' Set inputFile as file to be read from
Dim row, column, outline
Dim fields '(7) '8 fields per line
inputFile.ReadAll 'read to end of file
outline = ""
ReDim MyArray(inputFile.Line-2,NoOfCols) 'current line, minus one for header, and minus one for starting at zero
inputFile.close 'close file so that MyArray can be filled with data starting at the top
Set inputFile = FileSysObj.OpenTextFile(strDIR & strCSVFullFile, ForReading, True) 'back at top
strheadLine = inputFile.ReadLine 'skip header , but keep it for the output file
objOutFile.Write(strheadLine & vbCrLf)
anyBadlines = False
badlineflag = False
Do Until inputFile.AtEndOfStream
fullLine = inputFile.Readline
fields = Split(fullLine,",") 'store line in temp array
For column = 0 To NoOfCols-1 'iterate through the fields of the temp array
myArray(row,column) = fields(column) 'store each field in the 2D array with the given coordinates
'Wscript.Echo myArray(row,column)
if myArray(row,0) = " " or myArray(row,1) = " " then
badlineflag = True
'missline = myArray(row,0) & ", " & myArray(row,1) & ", " & myArray(row,2) & ", " & myArray(row,3) & ", " & myArray(row,4) & ", " & myArray(row,5) & ", " & myArray(row,6) & ", " & myArray(row,7)
'Wscript.Echo missline
'Exit For
end if
if column = NoOfCols-1 then
outline = outline & myArray(row,column) & vbCrLf
else
outline = outline & myArray(row,column) & ","
'csvFile = Regex.Replace(csvFile, "(,\s*?"".*?)(,)(\s+.*?""\s*?,)", "$1$3") 'TEST
end if
Next
cntAllLines = cntAllLines + 1
' Wscript.Echo outline
if badlineflag = False then
objOutFile.Write(fullLine & vbCrLf)
else
' write it somewhere else, drop a header in the first time
if anyBadlines = False Then
objOutFileM.Write(strheadLine & vbCrLf)
End if
objOutFileM.Write(outline)
cntBadLines = cntBadLines + 1
badlineflag = False
anyBadlines = True
end if
outline = ""
row = row + 1 'next line
Loop
objOutFile.Close
objOutFileM.Close
inputFile.close
Wscript.Echo "Total lines in the transaction file = " & cntAllLines
Wscript.Echo "Total bad lines in the file = " & cntBadLines
The below line is able to work as it contains 7 commas (8 columns).
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,ABC
The below line will throw an error as a result of more commas than 7 in the script.
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,Redburn, Europe. Limited
If greater than 7 commas in the CSV file line, the aim is to wrap it all greater than 7 into one field.
E.g. how do you replace Redburn, Europe. Limited string with double quotes as it is one name.
For example, in a text file it would appear like below:
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,"Redburn, Europe. Limited"
Is there a way to write a VB or VBA script to do the above and save it as a .csv file (which is opened via notepad to check the double quotes)?
Option Explicit
Option Compare Text
Public Sub ConvertFile()
Dim lngRowNumber As Long
Dim strLineFromFile As String
Dim strSourceFile As String
Dim strDestinationFile As String
strSourceFile = "U:\Book3.csv"
strDestinationFile = "U:\Book4.csv"
Open strSourceFile For Input As #1
Open strDestinationFile For Output As #2
lngRowNumber = 0
Do Until EOF(1)
Line Input #1, strLineFromFile
strLineFromFile = Right(Replace(strLineFromFile, ",", " ", 1), 1000)
Write #2, strLineFromFile
strLineFromFile = vbNullString
Loop
Close #1
Close #2
End Sub
As I see, you use MS Access (due to Option Compare Text line), so there is better built-in instruments for this task.
Use DoCmd.TransferText for it.
1st step is to create output specification via:
Here you can setup delimiters, even that differs from ", and handle other options.
After that you can use your set-up specification via following command
DoCmd.TransferText acExportDelim, "TblCustomers_export_spec", "TblCustomers", "C:\test\1.txt", True
In this case all characters escaping would be done through built-in instruments. It seems to be more easier to correct this code further.
As mentioned, there is VBScript workaround. For given input data, following function will do desired actions for given string:
Option Explicit
Function funAddLastQuotes( _
strInput _
)
Dim arrInput
arrInput = Split(strInput, ",")
Dim intArrSize
intArrSize = UBound(arrInput)
Dim intCurrentElement
Dim strOutput
Dim intPreLastElement
intPreLastElement = 6
For intCurrentElement = 1 To intPreLastElement
strOutput = strOutput & "," & arrInput(intCurrentElement)
Next
Dim strOutputLastField
For intCurrentElement = intPreLastElement + 1 To intArrSize
strOutputLastField = strOutputLastField & "," & arrInput(intCurrentElement)
Next
strOutputLastField = Right(strOutputLastField, Len(strOutputLastField) - 1)
strOutput = Right(strOutput, Len(strOutput) - 1)
strOutput = strOutput & "," & """" & strOutputLastField & """"
funAddLastQuotes = strOutput
End Function
MsgBox funAddLastQuotes("RXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,Redburn, Europe,,, Limited")
Finally, here is working VBScript solution.
Option Explicit
Const ColumnsBeforeCommadColumn = 6
Function funAddLastQuotes( _
strInput _
)
Dim arrInput
arrInput = Split(strInput, ",")
Dim intArrSize
intArrSize = UBound(arrInput)
Dim intCurrentElement
Dim strOutput
Dim intPreLastElement
intPreLastElement = ColumnsBeforeCommadColumn
For intCurrentElement = 1 To intPreLastElement
strOutput = strOutput & "," & arrInput(intCurrentElement)
Next
Dim strOutputLastField
If (intPreLastElement + 1) < intArrSize _
Then
For intCurrentElement = intPreLastElement + 1 To intArrSize
strOutputLastField = strOutputLastField & "," & arrInput(intCurrentElement)
Next
Else
strOutputLastField = strOutputLastField & "," & arrInput(intArrSize)
End If
strOutputLastField = Right(strOutputLastField, Len(strOutputLastField) - 1)
strOutput = Right(strOutput, Len(strOutput) - 1)
strOutput = strOutput & "," & """" & strOutputLastField & """"
funAddLastQuotes = strOutput
End Function
Public Sub ConvertFile( _
strSourceFile _
)
Dim objFS
Dim strFile
Dim strTemp
Dim ts
Dim objOutFile
Dim objFile
Set objFS = CreateObject("Scripting.FileSystemObject")
Dim strLine
Dim strOutput
Dim strRow
strFile = strSourceFile
strTemp = strSourceFile & ".tmp"
Set objFile = objFS.GetFile(strFile)
Set objOutFile = objFS.CreateTextFile(strTemp,True)
Set ts = objFile.OpenAsTextStream(1,-2)
Do Until ts.AtEndOfStream
strLine = ts.ReadLine
objOutFile.WriteLine funAddLastQuotes(strLine)
Loop
objOutFile.Close
ts.Close
objFS.DeleteFile(strFile)
objFS.MoveFile strTemp,strFile
End Sub
ConvertFile "C:\!accsoft\_in.csv"
You should change following part: ConvertFile "C:\!accsoft\_in.csv as path to your file.
And ColumnsBeforeCommadColumn = 6 is the setting, at which column the chaos with commas begins

vba macro display result of loop to msgbox

I creted a loop checking number of characters length with conditions but sadly it's not properly working,
with approriate no. of loops but not reading the next line, I want to post the result in a MsgBox,
but when I use the msgbox inside the loop I will get a msgbox for every result found or only one msgbox with one result.
What I would like is to display every result in 1 msgbox with a line vbNewLine after each result.
Below is my code:
Public Sub Rs()
Dim Text As String
Dim NumChar As String
Dim i As Integer
Dim NumRows As Long
Application.ScreenUpdating = False
'Get Cell Value
Text = Range("B2").Value
'Get Char Length
NumChar = Len(Text)
NumRows = Range("B2", Range("B2").End(xlDown)).Rows.Count
Range("B2").Select
For i = 1 To NumRows
'Character length validation
If Len(Text) <= 15 Then
MsgBox Chr(149) & " SVC_DESC " & Text & " has " & NumChar & " characters " & " and it's Valid !" & vbNewLine
Else
MsgBox Chr(149) & " SVC_DESC " & Text & " has " & NumChar & " characters " & " and Exceeded allowable number of characters!" & vbNewLine
End If
Next i
Application.ScreenUpdating = True
End Sub
Assign the new text to a string variable and display the string variable outside the loop:
Option Explicit
Sub TestMe()
Dim i As Long
Dim displayText As String
For i = 1 To 3
displayText = displayText & vbCrLf & i
Next i
MsgBox displayText
End Sub
Build a string through concatenation and display the strings after exiting the loop.
Public Sub Rs()
Dim Text As String
Dim NumChar As String
Dim i As Integer
Dim NumRows As Long
dim msg1 as string, msg2 as string
Application.ScreenUpdating = False
'Get Cell Value
Text = Range("B2").Value
'Get Char Length
NumChar = Len(Text)
NumRows = Range("B2", Range("B2").End(xlDown)).Rows.Count
Range("B2").Select
For i = 1 To NumRows
'Character length validation
If Len(Text) <= 15 Then
msg1 = msg1 & Chr(149) & " SVC_DESC " & Text & " has " & NumChar & " characters " & " and it's Valid !" & vbLF
Else
msg2 = msg2 & Chr(149) & " SVC_DESC " & Text & " has " & NumChar & " characters " & " and Exceeded allowable number of characters!" & vbLF
End If
Next i
Application.ScreenUpdating = True
if cbool(len(msg1)) then
msg1 = left(msg1, len(msg1)-1)
MsgBox msg1
end if
if cbool(len(msg2)) then
msg2 = left(msg2, len(msg2)-1)
MsgBox msg2
end if
End Sub
A MsgBox uses Chr(10) aka vbLF for new lines; vbNewLine is overkill.

VBA Multiple FreeFile Exports to CSV

I'm trying to use the Freefile to export to text files. The process is taking a worksheet with many columns and for each column, exporting it as text.
The problem I've been having is getting the error 55 code "file is already open".
Because I want the column range as the input to be of a variable length, I don't know for certain how many freefile commands I would need.
For j = intColumOffsett + 1 To intLastColumn
strDate = wkSource.Cells(1, j).Value
strNewFile = strDirectory & strDate & " New.csv"
For i = 1 To intLastRow
strTarget = strTarget & wkSource.Cells(i, 1).Value & ","
strTarget = strTarget & wkSource.Cells(i, 2).Value & ","
strTarget = strTarget & wkSource.Cells(i, 3).Value & ","
strTarget = strTarget & strDate & ","
strTarget = strTarget & wkSource.Cells(i, j).Value
' It's this this section I'm not sure about \/
'Set strNewFile = Nothing
'Stop
iF1 = FreeFile(j)
'Close #iF1
On Error GoTo Error:
Open strNewFile For Output As #iF1
Print #iF1, strTarget
Debug.Print strTarget
strTarget = ""
Error:
MsgBox (Err.Description)
Next i
Close #iF1
Next j
How can I avoid these errors will exporting as many new CSV's as I needed depending on the unknown number of columns from the source....?????
FreeFile will generate a new file number each time you call it.
But in your code, you were calling it for each row.
And you error handling wasn't appropriate, so I added a sub to show how you should use! ;)
Sub MultiFreeFiles()
'''...
For j = intColumOffsett + 1 To intLastColumn
strDate = wkSource.Cells(1, j).Value
strNewFile = strDirectory & strDate & " New.csv"
iF1 = FreeFile
On Error GoTo Error:
Open strNewFile For Output As #iF1
For i = 1 To intLastRow
strTarget = vbNullString
With wkSource
strTarget = strTarget & .Cells(i, 1).Value & ","
strTarget = strTarget & .Cells(i, 2).Value & ","
strTarget = strTarget & .Cells(i, 3).Value & ","
strTarget = strTarget & strDate & ","
strTarget = strTarget & .Cells(i, j).Value
End With 'wkSource
Debug.Print strTarget
Print #iF1, strTarget
Next i
Close #iF1
Next j
'''...
Exit Sub
Error:
MsgBox (Err.Description)
Resume
End Sub

Removing White Space

I need help creating separate text files from each row in an excel spread sheet called "worksheet". I want the text files to be named with content of Column A + “Result”+ Column H (Which should be hidden in the .txt file, with columns B-G being the content, I have done the coding. Please find the followings. But I have received whitespace in the .txt output file. Please find the screenshots. I am unable to TRIM this white space.
How would I proceed further to solve the problem?
Thanks in Advance.
VBA Code:
Sub WriteTotxt()
Const forReading = 1, forAppending = 3, fsoForWriting = 2
Dim fs, objTextStream, sText As String
Dim lLastRow As Long, lRowLoop As Long, lLastCol As Long, lColLoop As Long
lLastRow = Cells(Rows.Count, 1).End(xlUp).Row
For lRowLoop = 1 To lLastRow
Set fs = CreateObject("Scripting.FileSystemObject")
Set objTextStream = fs.opentextfile("D:\EXCEL_TXT_TEST\New folder\" & Cells(lRowLoop, 8) & "-" & "RESULT" & "-" & Cells(lRowLoop, 1) & ".txt", fsoForWriting, True)
sText = ""
sText1 = ""
For lColLoop = 1 To 7
If lColLoop <> 7 Then
sText = sText & "<" & Cells(lColLoop) & ">" & "," & Chr(0)
sText1 = sText1 & Cells(lRowLoop, lColLoop) & "," & Chr(0)
Else
sText = sText & "<" & Cells(lColLoop) & ">" & Chr(0)
sText1 = sText1 & Cells(lRowLoop, lColLoop) & Chr(0)
End If
Next lColLoop
objTextStream.writeline (Left(sText, Len(Trim(sText)) - 1))
objTextStream.writeline (Left(sText1, Len(Trim(sText1)) - 1))
objTextStream.Close
Set objTextStream = Nothing
Set fs = Nothing
Next lRowLoop
End Sub
You can remove all the blank lines from a string like this
mystr = replace(mystr, vblf & vbcr, "")
This will remove empty lines, not lines that contain spaces or other characters you can't see though..
I can help with your code as well, but have you tried a simple approach first?
Why don't you just file --> save as .csv, and replace your header? Your data output will be VERY similar, save for the " " space preceding your listed entries. Lazy but easy.
adapt this to your module, and you can erase like everything you have ...
ActiveWorkbook.SaveAs Filename:= _
"c:\MyFile.csv", FileFormat:=xlCSV _
, CreateBackup:=False
Then, just read your data back in, and string operations will be easy.

Word split fails with more then 3 words

I try to split a string every + then every |, it works fine when I try to read only 3 words from the split words1(0-3), but when I try to read words1(4) the whole function fails... here is the code:
Private Function SetUpdateData()
Try
Dim delimiterChars As Char() = {"+"c}
Dim words As String() = updatelist.Split(delimiterChars)
Dim i As Integer = 1
Do While (i < words.Length)
Dim delimiterChars1 As Char() = {"|"c}
Dim words1 As String() = words(i).Split(delimiterChars1)
Dim name As String = words1(0)
Dim version As String = words1(1)
Dim fileurl As String = words1(2)
Dim size As String = (words1(3) / 1024D / 1024D).ToString("0.00") & " MB"
Dim cversion As FileVersionInfo = FileVersionInfo.GetVersionInfo(Path.Combine(Directory.GetCurrentDirectory() & "\" & name))
If My.Computer.FileSystem.FileExists(Directory.GetCurrentDirectory() & "\" & name) Then
If Not version.Contains(cversion.FileVersion) Then
DataGridView1.Rows.Add(name, version, size)
RichTextBox1.AppendText("+" & words1(0) & "|" & words1(1) & "|" & words1(2) & "|" & words1(3))
End If
Else
DataGridView1.Rows.Add(name, version, size)
RichTextBox1.AppendText("+" & words1(0) & "|" & words1(1) & "|" & words1(2) & "|" & words1(3))
End If
i = (i + 1)
Loop
Catch ex As Exception
MsgBox("error")
End Try
End Function
This above works no problem at all, but when you add words1(4) in like this:
Private Function SetUpdateData()
Try
Dim delimiterChars As Char() = {"+"c}
Dim words As String() = updatelist.Split(delimiterChars)
Dim i As Integer = 1
Do While (i < words.Length)
Dim delimiterChars1 As Char() = {"|"c}
Dim words1 As String() = words(i).Split(delimiterChars1)
Dim name As String = words1(0)
Dim version As String = words1(1)
Dim fileurl As String = words1(2)
Dim size As String = (words1(3) / 1024D / 1024D).ToString("0.00") & " MB"
Dim status As String = words1(4)
Dim cversion As FileVersionInfo = FileVersionInfo.GetVersionInfo(Path.Combine(Directory.GetCurrentDirectory() & "\" & name))
If My.Computer.FileSystem.FileExists(Directory.GetCurrentDirectory() & "\" & name) Then
If Not version.Contains(cversion.FileVersion) Then
DataGridView1.Rows.Add(name, version, size)
RichTextBox1.AppendText("+" & words1(0) & "|" & words1(1) & "|" & words1(2) & "|" & words1(3) & "|" & words(4))
End If
Else
DataGridView1.Rows.Add(name, version, size)
RichTextBox1.AppendText("+" & words1(0) & "|" & words1(1) & "|" & words1(2) & "|" & words1(3) & "|" & words(4))
End If
i = (i + 1)
Loop
Catch ex As Exception
MsgBox("error")
End Try
End Function
ALSO the string that it is splitting is:
+Thing v2.exe|1.0.0.1|http://example.com/uploads/Thing v2.exe|205824|Primary+Thing v2 DLL.dll|1.0.0.1|http://example.com/uploads/Thing DLL.dll|1097728|Secondary
Which all should output:
words1(0) - Thing v2.exe
words1(1) - 1.0.0.1
words1(2) - http://example.com/uploads/Thing v2.exe
words1(3) - 205824
words1(4) - Primary
But as I said above once words1(4) is used it crashes the whole function...
It will catch and fail and give the error message, but when I try to do msgbox(ex) for the exception error, no msgbox pops up and the program just continues.
If anyone can fix the issue or give me some help that would be greatly appreciated, thanks in advance and sorry if this is confusing as it is to me too!
There are two loops in your program:
Loop1:
words1(0)>>Thing v2.exe
words1(1)>>1.0.0.1
words1(2)>>http://example.com/uploads/Thing v2.exe
words1(3)>>205824
words1(4)>>Primary
Loop2:
words1(0)>>Thing v2 DLL.dll
words1(1)>>1.0.0.1
words1(2)>>http://example.com/uploads/Thing DLL.dll
words1(3)>>1097728
words1(4)>>Secondary
it appears that you misspelled your words1(4) to words(4) in below line
RichTextBox1.AppendText("+" & words1(0) & "|" & words1(1) & "|" & words1(2) & "|" & words1(3) & "|" & words(4))
Your split functionality works fine but there's an error on the following lines (there are 2 of them):
RichTextBox1.AppendText("+" & words1(0) & "|" & words1(1) & "|" & words1(2) & "|" & words1(3) & "|" & words(4))
The last words(4) should be words1(4).