Very strange Find/Replace behaviour - vba

I have a Firebird database stored in Windows-1251 codepage and managed using IBExpert. I have to get some billing info using SQL, edit it and then send it to clients. I export query results into .csv (comma-separated values) format and then process a bunch of csvs into a pretty xls (with borders, fonts, etc.) using Microsoft Excel 2010. I have NO idea why, but IBExpert places a strange symbol everywhere in numeric values between decades (64 731 instead of 64731). Asc() method from VBA tells me that it's the #160 symbol in ASCII codepage.
NOW, the strangest observation I made: if you copy this symbol manually and delete it from everywhere using find/replace function of Excel, everything is OK. If you do the same thing in any text editor (e.g. good old notepad) everything is still OK. But when you try to automate the replacement using VBA, everything goes very, very wrong. No matter if you use a manually copied #160 from the csv itself or you generate it using Chr(160), if you try to delete all those, VBA also deletes half of the commas. By comma I mean generally known symbol #44, you can google "ascii" pictures and check it out. I have to mark that again, the replacement affects half the commas, however all of them actually ARE the very same symbol, I rechecked that twice.
You can look for a link to a csv below, so you can reassure yourself with the fact that I'm not crazy.
Here is the code you can use to reproduce the magic
Sub test()
Worksheets(1).UsedRange.Replace What:=Chr(160), Replacement:=""
End Sub
I'll be very thankful to someone who will clarify this phenomenon, because I just can't believe that VBA is that buggy, I think I missed something somewhere
UPDATE: Guys, I am terribly sorry. I'm so dumb that I've uploaded the wrong csv. Here's the right one

I've imported the CSV to Range("A1"). Here's what I've found:
$F$2 = 4 708,200
That value is not detected as a numeric. This is due to the CHR(160) existing in the 2nd place (the "space" after 4).
If you want that value to become 4708200 (four million...), replace CHR(160) like you've done. This removes the comma because now excel detects those values as numerics.
Since you haven't provided correct info, Excel thinks the comma is a thousands separator.
If it should rather be 4708,2 (four thousand...), correct it during your CSV import:
To import the CSV correctly, you have to put CHR(160) as a thousands separator.
The comma will act as a decimal sign.
This way, Excel will interpret 4 708,200 as the numeric value 4708,2 during import.
When using REPLACE in VBA, Excel assumes the comma is a thousands separator. Why? Hard to say. However, you haven't provided that it's NOT. :)
Below is the code for importing the file correctly.
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;H:\testfile2.csv", Destination:=Range("$A$1"))
.Name = "testfile2.csv"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 1251
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = True
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1)
.TextFileThousandsSeparator = Chr(160) ' Here's that thousands separator!
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
Update: Here's the code that replaces your previous Workbooks.OpenText macro.
Sub eyecandy()
Dim SelectedItem
Dim Wb As Workbook, Sh As Worksheet
Dim WbName As String, WbFullName As String
With Application.FileDialog(msoFileDialogFilePicker)
.Title = " "
.InitialFileName = ThisWorkbook.Path & Application.PathSeparator & "*.csv"
.AllowMultiSelect = True
If .Show = False Then Exit Sub
Application.ScreenUpdating = False
For Each SelectedItem In .SelectedItems
Set Wb = Workbooks.Add
' Get the file name
WbFullName = Replace(SelectedItem, ThisWorkbook.Path & Application.PathSeparator, "")
WbName = Replace(WbFullName, ".csv", "")
' Deletes unnecessary sheets
Do Until Wb.Sheets.Count = 1
Application.DisplayAlerts = False
Wb.Sheets(1).Delete
Application.DisplayAlerts = True
Loop
Set Sh = Wb.Sheets(1)
With Sh.QueryTables.Add(Connection:= _
"TEXT;" & SelectedItem, Destination:=Sh.Range("$A$1"))
.Name = WbName
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 1251
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = True
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1)
.TextFileThousandsSeparator = Chr(160)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
Sh.Activate
ActiveWindow.DisplayGridlines = False
With Sh.UsedRange
.Borders.LineStyle = xlContinuous
.Rows(1).Font.Bold = True
.Rows(1).Borders.Weight = xlThick
End With
Sh.Name = WbName
Wb.SaveAs Filename:=WbName, FileFormat:=56
Wb.Close SaveChanges:=False
Next SelectedItem
Application.ScreenUpdating = True
End With
End Sub

So, as #takl suggested, the solution was to modify thousand separator property.
It's .TextFileThousandsSeparator if you are using ActiveSheet.QueryTables.Add method and .ThousandsSeparator if you are using Workbooks.OpenText method.
I really appreciate his help, but I just have to use the Workbooks.OpenText method because it supports Local property. So, here's the edited file-processing loop from my script
'walk through selected files
For Each SelectedItem In .SelectedItems
Workbooks.OpenText _
Filename:=SelectedItem, _
Origin:=xlWindows, _
StartRow:=1, _
DataType:=xlDelimited, _
TextQualifier:=xlTextQualifierNone, _
ConsecutiveDelimiter:=False, _
Semicolon:=True, _
ThousandsSeparator:=Chr(160), _
Local:=True

Related

How would I open a .csv file with VBA and read all the data?

When I extract my data from this one software into raw text it separates the values with commas and quotation marks for the majority of the file. Except in certain cases the data has a line break. When I save it as a .csv and open it, the data is cleanly formatted into a proper table.
However, if I attempt the same process with QueryTablesit processes the enter character as a new line.
I have two different approaches in two different subprograms
The first is able to read the number of rows and columns properly, but since it uses the QueryTables method it reads that enter charachter as a new line.
The code for this approach is below:
Private Sub OpenCSVFile()
With ThisWorkbook
Set primeSheet = .Sheets.Add(After:=.Sheets(.Sheets.Count))
primeSheet.Name = "Temp"
End With
Set informationRange = primeSheet.Range("A1")
xAddress = informationRange.Address
With primeSheet.QueryTables.Add("TEXT;" & strPath, primeSheet.Range(xAddress))
.AdjustColumnWidth = False
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = False
.RefreshOnFileOpen = False
.RefreshStyle = xlOverwriteCells
.SaveData = False
.RefreshPeriod = 0
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
rowLength = primeSheet.Cells(1, Columns.Count).End(xlToLeft).Column
colLength = primeSheet.Cells(Rows.Count, "A").End(xlUp).Row
End Sub
The other method keeps the formatting intact as to when I regularly open .csv files of my extracted data, but it is unable to read the number of rows and lengths, and returns a value for 1 for each.
Private Sub OpenCSV()
Set primeBook = Workbooks.Open(strPath)
With primeBook
rowLength = Sheet1.Cells(1, Columns.Count).End(xlToLeft).Column
colLength = Sheet1.Cells(Rows.Count, "A").End(xlUp).Row
End With
Set informationRange = Sheet1.Range("A1", Sheet1.Cells(colLength, rowLength))
End Sub
How would you recommend I address my issue and read the contents of the csv file while ensuring no weird line breaks.
Would this work?
Private Sub OpenCSV()
Set primeBook = Workbooks.Open(strPath)
With primeBook.Sheet1
rowLength = .usedrange.rows.count
colLength = .usedrange.columns.count
End With
Set informationRange = Sheet1.Range("A1", Sheet1.Cells(colLength, rowLength))
End Sub

Import Data from Text File into Master File (changing target directories)- Excel

I know that this post is going to seem very similar to many other posts to those who understand it. I have learned C++ and C#, both only well enough to do minor work, and I just cannot understand VBA well enough to make this macro happen.
I have just under 100 files that need to be imported to a master file. I cannot modify the source files but the master file needs only select columns.
This macro works almost perfectly I just need the ability to select new file paths for each instance of the macro being used. I have found many posts that seem to use something like this:
https://social.msdn.microsoft.com/Forums/office/en-US/231cbfc5-95ad-4673-a20c-f87355c6bc5e/prompt-user-for-file-name-to-import-as-fixed-width-text-file?forum=exceldev
in order to first make a filepath into a variable and then pass it to the ActiveSheet.QueryTables.Add command. I might just be missing something but there are a lot of variables between all of the examples that I just don't understand. It seems like the msdn page for vba is much less intuitive than those for C#. Either that or I am simply unable to understand them having not taken the babysteps that I need.
Using the macro tool I made the large majority of the code below. About an hour of working allowed me to replace the hardcoded cell with the active cell.
Sub InputDataFromTextFile()
'
' InputDataFromTextFile Macro
'
' Keyboard Shortcut: Ctrl+t
'
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;E:\Dropbox\College 2016-2017\Research\Buffered Solutions\pH10\With PDADMAC\30.CSV" _
, Destination:=ActiveCell)
.Name = "30"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 1252
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(9, 1, 9)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub
I would appreciate any and all help that could be given. Thank you all so much for your time regardless.
So immediately after posting, I hadn't figured it out in the comments I tried something and got it to work. Here is the code as it stands.
Sub InputDataFromTextFile()
Dim Filt As String
Dim FilterIndex As Integer
Dim Title As String
Dim FileName As Variant
' Set up list of file filters
Filt = "All Files (*.*),*.*"
' Display Text Files by default
FilterIndex = 1
' Set the dialog box caption
Title = "Select a File to Import"
' Get the file name
FileName = Application.GetOpenFilename _
(FileFilter:=Filt, _
FilterIndex:=FilterIndex, _
Title:=Title)
' Exit if dialog box is canceled
If FileName = False Then
MsgBox "No file was selected."
Exit Sub
End If
'
' InputDataFromTextFile Macro
'
' Keyboard Shortcut: Ctrl+t
'
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;" & FileName, _
Destination:=ActiveCell)
.Name = "30"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 1252
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(9, 1, 9)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub
One of my largest issues was honestly that once excel was restarted the Ctrl+T that I had hotkeyed to the command reverted to making a table. I couldn't figure out where it was coming from! Thank you for your help. This saves me a great deal of time.
While the comment made by Parfait about cycling through the files and having them auto import is the next step and a very obviously desired trait in the code, it seems like a lot for me right now. I'm already saving upwards of an hour per mastersheet which is just amazing. Thank you all so much again.

Error parsing CSV to XLS with VBA script

This function is designed to open a CSV file, and import all the data into a specific Sheet on an Excel Workbook.
But I think there is some kind of problem I can't resolve in some cases with delimiters.
This is my function:
Sub LoopAllExcelFilesInFolder_Invenotry()
Dim strFilename As String
Dim wsMstr As Worksheet: Set wsMstr = ThisWorkbook.Sheets("ALL_ACTIUS")
If MsgBox("Erase sheet before start importing?", vbYesNo, "Delete?") _
= vbYes Then wsMstr.UsedRange.Clear
strFilename = Application.GetOpenFilename _
(FileFilter:="CSV File (*.csv), *.csv", _
Title:="Select CSV file: ")
Worksheets("ALL_MACHINES").Activate
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;" & strFilename, _
Destination:=Range("A1"))
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 1252
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = True
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub
This is part of the source code (CSV file), containing a line that is not beeing "translted" as expected:
Here you can see how this line is translated to the Excel. The 12X5" string should'nt be there. The first column should only contain IP addresses.
I'm pretty sure It's a delimiter character issue, but I can't find the solution.
The Workbooks.Open command worked for me with that issue.
Dim wb As Workbook
strFilename = "yourfilename.csv"
Set wb = Workbooks.Open(Filename:=strFilename, local:=True)

ADO text file query - results split by comma

I am querying a text file using ADO to bring the data into Excel.
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & filePath & ";" & _
"Extended Properties='text';"
rs.Open "SELECT * FROM " & fileName, cn
wsImport.Range("A1").CopyFromRecordset rs
The issue I'm facing is that the query results are being split, by comma as a delimiter. This means that when I write the data to the worksheet, it's being output across several columns.
I've confirmed that it's being split at the query stage, and not at the writing of the data to the worksheet stage. I have to use rs.Fields(0) and rs.Fields(1) to access some rows of data, when I want all of the data to be accessible within the first field of the created recordset (allowing the data to be written to column A of the worksheet).
Can anyone clarify how I can query the text file, whilst not splitting the data by any delimiter?
I've also tried using the below within the Extended Properties.
Extended Properties='text;HDR=Yes;FMT=Delimited';
and
Extended Properties='text;HDR=Yes;FMT=FixedLength';
Here's a simple example of reading the text file:
Sub foo(filePath As String)
Dim sDataIn As String
Dim sDataTemp() As String
Dim sDataOut() As String
Dim n As Long
Open filePath For Binary As #1
sDataIn = Space$(LOF(1))
Get #1, , sDataIn
Close #1
sDataTemp() = Split(sDataIn, vbNewLine)
ReDim sDataOut(1 To UBound(sDataTemp) + 1, 1 To 1)
For n = LBound(sDataTemp) To UBound(sDataTemp)
sDataOut(n + 1, 1) = sDataTemp(n)
Next n
ActiveSheet.Range("A1").Resize(UBound(sDataOut), 1) = sDataOut
End Sub
If you turn on the macro recorder and let it record you doing all the steps one time to import a file, you should have your answer.
I just tried it and got this.
Sub Macro1()
'
' Macro1 Macro
'
' Keyboard Shortcut: Ctrl+s
'
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;C:\Users\your_path_here\test.txt", Destination:=Range("$A$1"))
.CommandType = 0
.Name = "test"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileColumnDataTypes = Array(1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub

User click on cell, prompts user to locate text file. Cell value contains path to file location

I have a text data file that I download to a location on my computer. Right now, in my VBA script, I have the path hard coded. What I would want, if this is possible is for the user to click a cell (C5) in worksheet "Main" in this case and when he/she does, a dialogue pops up to prompt user to navigate to the text file and select it. After the user selects the text file, I want the cell C5 value to hold the file path of the text file.
I would like the value of C5 to be substituted in for the hardcoded file path that I have in my VBA script:
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;\\psf\Home\Desktop\Temp\sample.txt", Destination:=Range( _
"$A$1"))
.Name = "fills"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = True
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
I want the value of C5 to go into the part after Connection:= part which I do not know how to do as of yet and would like help/input as well.
Is this possible to do?
The code below will run when a user right clicks C5
Part 1
Right click your sheet tab
View Code
Copy and past in the code below
code
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Dim strFileToOpen As String
If Target.Address(0, 0) <> "C5" Then Exit Sub
strFileToOpen = Application.GetOpenFilename _
(Title:="Please choose a file to place in C5 (pick Open)", _
FileFilter:="Text Files *.txt (*.txt),"
If strFileToOpen = "False" Then
[c5].Value2 = "No file selected"
Else
[c5].Value2 = strFileToOpen
End If
End Sub
Part 2
change
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;\\psf\Home\Desktop\Temp\sample.txt", Destination:=Range( _
"$A$1"))
to
With ActiveSheet.QueryTables.Add(Connection:= _
"TEXT;" & [c5].value2 & "", Destination:=Range( _
"$A$1"))