The 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
Answer:
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
ss:
Tags: excelexcel, string, text, vba