TextToColumns method of the
Range object automatically converts strings to numbers, but it would be nice to suppress this feature. The method has a
TextQualifier parameter, but it doesn’t seem to do what I’m looking for. The following data illustrates the issue. Strings in column A are delimited with semicolons that separate a text part from a number part. Note that the numbers all begin with zero, and that numbers in row 4-6 are prefixed with an apostrophe:
Column A StringRow1;01000 StringRow2;02000 StringRow3;03000 StringRow4;'01000 StringRow5;'02000 StringRow6;'03000
The following macro splits the strings into a text part in Column B and a number part in Column C.
Sub TTC() Application.DisplayAlerts = False Dim rToSplit As Range Set rToSplit = ThisWorkbook.Worksheets(1).Range("A1:A6") rToSplit.TextToColumns _ Destination:=Range("B1"), _ DataType:=xlDelimited, _ Semicolon:=True, _ TextQualifier:=xlTextQualifierNone End Sub
The last column illustrates the desired output:
Column A Column B Column C Data Output Output Desired Output StringRow1;01000 StringRow1 1000 01000 StringRow2;02000 StringRow2 2000 02000 StringRow3;03000 StringRow3 3000 03000 StringRow4;'01000 StringRow4 '01000 01000 StringRow5;'02000 StringRow5 '02000 02000 StringRow6;'03000 StringRow6 '03000 03000
I have tried formatting column C ahead of the split, like this:
rToSplit.Offset(, 3).NumberFormat = "@", but it has no effect. Switching the
TextQualifier parameter to
xlTextQualifierSingleQuote has the effect of treating rows 4-6 in the same way as rows 1-3.
Am I asking for the impossible? Or is there maybe some application level setting I’m not aware of? Or could I do something smart with the strings in column A?
(I could of course loop through Column C after the split and fix the issue, but for large data sets that’s not attractive. For my particular application, the strings in column A are generated by code that searches for patterns in tens of thousands of text rows in several different text files; each match is added to a dictionary and then I use
array() = Dictionary.Items and
DestinationRange.Value = Application.WorksheetFunction.Transpose(array) to read the data to the worksheet. This is very fast. My workaround to deal with the issue described here is to save the number strings in a separate dictionary which is read to column C after the split. This works well, so I posted this out of curiosity to see what I can learn…)
You can use the FieldInfo property to set the data type for each column. You will need to know how many columns you have beforehand though, or know which column will contain the numbers.
The FieldInfo parameter takes an array of arrays, with each of the sub-arrays having 2 values. The first value represents the column number (starting at 1), and the second number is the XLColumnDataType you would like that column to be formatted as.
In this case, you’d like everything to be formatted as text (instead of a number, like it’s currently doing), so you would use xlTextFormat (this is just a system defined constant equal to 2).
x.TextToColumns _ Destination:=Range("B1"), _ DataType:=xlDelimited, _ Semicolon:=True, _ TextQualifier:=xlTextQualifierNone, _ FieldInfo:=Array(Array(1, xlTextFormat), Array(2, xlTextFormat)) 'Format columns 1 and 2 as text
If you are willing to do it with a loop:
Sub TTC() Dim row As Long, lastRow As Long, splitSpot As Integer, cellValue As String Application.ScreenUpdating = False With ThisWorkbook.Worksheets(1) lastRow = .Cells(.Rows.Count, "A").End(xlUp).row For row = 1 To lastRow cellValue = CStr(.Range("A" & row).Value) splitSpot = InStr(cellValue, ";") .Range("B" & row & ":C" & row).NumberFormat = "@" .Range("B" & row).Value = Left(cellValue, splitSpot - 1) If Mid(cellValue, splitSpot, 1) = "'" Then .Range("C" & row).Value = Right(cellValue, Len(cellValue) - splitSpot + 1) Else .Range("C" & row).Value = Right(cellValue, Len(cellValue) - splitSpot) End If Next End With End Sub