I'm using text to columns as part of a VBA macro to separate timestamps into 2 other columns. When I format Column B to dd/mm/yyyy it uses the current year 2020 instead of 2019. Is there a way to adjust my macro to pull the year from the original timestamp or alternatively, pull the year from Column C once Text to Columns has completed?
Range("A5").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.TextToColumns Destination:=Range("A5"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=False, Comma:=True, Space:=False, Other:=False, FieldInfo _
:=Array(Array(1, 3), Array(2, 3), Array(3, 3)), TrailingMinusNumbers:=True
Range("B5").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.NumberFormat = "dd/mm/yyyy;#"
Selection.TextToColumns Destination:=Range("B5"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=False, Comma:=True, Space:=False, Other:=False, FieldInfo _
:=Array(1, 8), TrailingMinusNumbers:=True
This uses arrays:
Sub mydatesplit()
With ActiveSheet
Dim arr As Variant
arr = .Range("A5", .Cells(.Rows.Count, 1).End(xlUp)).Value
Dim outArr() As Variant
ReDim outArr(1 To UBound(arr, 1), 1 To 3)
Dim i As Long
For i = 1 To UBound(arr, 1)
Dim spltStr() As String
spltStr = Split(Replace(arr(i, 1), ",", ""), " ")
If UBound(spltStr) >= 5 Then
outArr(i, 1) = spltStr(0)
outArr(i, 2) = DateValue(spltStr(2) & " " & spltStr(1) & " " & spltStr(3))
outArr(i, 3) = TimeValue(spltStr(4) & " " & spltStr(5))
End If
Next i
.Range("B5").Resize(UBound(outArr, 1), UBound(outArr, 2)).Value = outArr
End With
End Sub
After Running:
BTW with Dynamic Array formulas newly introduced into Excel with the latest subscription one can use fairly simple formula:
Date:
=--TEXTJOIN(" ",TRUE,INDEX(TRIM(MID(SUBSTITUTE(SUBSTITUTE(A5,",","")," ",REPT(" ",999)),(ROW($1:$7)-1)*999+1,999)),{3,2,4}))
Time
=--TEXTJOIN(" ",TRUE,INDEX(TRIM(MID(SUBSTITUTE(SUBSTITUTE(A5,",","")," ",REPT(" ",999)),(ROW($1:$7)-1)*999+1,999)),{5,6}))
Based on data in the screenshot you could use the following function to split the timestamp
Function convertTimestamp(ByVal inp As String) As Variant
Dim sDate As String, sTime As String, sTimezone As String, sDay As String
Dim v As Variant
v = Split(Replace(inp, ",", ""), " ")
sDate = DateValue(v(2) & " " & v(1) & " " & v(3))
sTime = TimeValue(v(4) & " " & v(5))
sTimezone = v(6)
sDay = v(0)
ReDim v(1 To 4)
v(1) = sDay
v(2) = CDate(sDate)
v(3) = sTime
v(4) = sTimezone
convertTimestamp = v
End Function
PS Adjusted the function based on Scott's excellent approach to split the string.
Either you use this function in the worksheet itself (as an array function!) or you use the following code to split the row 5 to 8 as in your screenshot
Sub TimeStampToCol()
Dim rg As Range
Set rg = Range("A5:A8")
Dim vDat As Variant
vDat = WorksheetFunction.Transpose(rg)
Dim rDat As Variant
ReDim rDat(1 To 4, 1 To 4)
Dim i As Long, v As Variant, j As Long
For i = LBound(vDat) To UBound(vDat)
v = convertTimestamp(vDat(i))
For j = 1 To 4
rDat(i, j) = v(j)
Next j
Next i
Set rg = Range("B5:E8")
rg.Value = rDat
End Sub
Usage as an array formula
Related
I am running the next VBA code:
`
`Sub ARMABASES()
'
' ARMABASES Macro
' Arma la base de inventario y producción de fianzas
'
' Acceso directo: Ctrl+Mayús+A
'
Dim MyDB As Variant
Dim MyDBP As Variant
'Dim MyData(1 To 1000000, 1 To 40) As Double
Dim Vecnames(1 To 10, 1 To 5) As String
'Dim MyMat(1 To 1368, 1 To 1525) As Double
Vecnames(1, 1) = Worksheets("DATOS").Range("B5").Value
Vecnames(1, 2) = Worksheets("DATOS").Range("B6").Value
Vecnames(1, 3) = Worksheets("DATOS").Range("B7").Value
Vecnames(1, 4) = Worksheets("DATOS").Range("B8").Value
Vecnames(1, 5) = Worksheets("DATOS").Range("B9").Value
Vecnames(2, 1) = Worksheets("DATOS").Range("B10").Value
Vecnames(2, 2) = Worksheets("DATOS").Range("B11").Value
Vecnames(3, 2) = Worksheets("DATOS").Range("B12").Value
Set SRC = Workbooks.Open(Vecnames(1, 5) & Vecnames(2, 1), 0, True, True)
Worksheets("Sheet1").Activate
Dim lRow As Integer
Dim lCol As Integer
Dim rng As Range
lRow = Range("A1048576").End(xlUp).Row
'use the lRow to help find the last column in the range
lCol = Range("XFD" & lRow).End(xlToLeft).Column
Set rng = Range(Cells(2, 1), Cells(lRow, lCol))
'msgbox to show us the range
' MsgBox "Range is " & rng.Address
MyDB = rng
SRC.Close False
Worksheets("Sheet1").Activate
Range(Cells(2, 1), Cells(lRow, lCol)) = MyDB
Range(Cells(2, 11), Cells(lRow, 11)).Select
Selection.TextToColumns Destination:=Range(Cells(2, 11), Cells(lRow, 11)), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _
:=Array(1, 4), TrailingMinusNumbers:=True
Selection.NumberFormat = "dd/mm/yyyy;#"
Set SRC = Workbooks.Open(Vecnames(1, 5) & Vecnames(2, 2), 0, True, True)
Worksheets("Sheet1").Activate
Dim lRowP As Integer
Dim lColP As Integer
Dim rngP As Range
lRowP = Range("A1048576").End(xlUp).Row
'use the lRow to help find the last column in the range
lColP = Range("XFD" & lRowP).End(xlToLeft).Column
' Set rngP = Range(Cells(2, 1), Cells(lRowP, lColP))
'msgbox to show us the range
'MsgBox "Range is " & rngP.Address
Erase MyDB
'MyDBP = rngP
MyDBP = Range(Cells(2, 1), Cells(lRowP, lColP))
SRC.Close False
Worksheets("Hoja1").Activate
Range(Cells(2, 1), Cells(lRowP, lColP)).Value = MyDBP
Range(Cells(2, 11), Cells(lRowP, 11)).Select
End Sub
When it gets to Range(Cells(2, 1), Cells(lRowP, lColP)).Value = MyDBP appears runtime error 7 out of memory; I can't find where the problem is, the array size is not important, but it seems there is a cell where it stops.
I have store arrays with at least 500,000 records and 60 columns; this one is not that big.
I hope someone can help me
I am getting a runtime error 1004: Method 'Range' of object '_Global' failed when running my code. It should be splitting the data in the source column into a destination specified by the first blank column in the array. Because the source data is erratically formatted it needs to look for tabs or line breaks as the delimiter. I am using variable names for the source and blank columns as they are not at a fixed position in the array.
Dim CurrentCol As Integer
Dim FirstCol As Integer
Dim LastCol As Integer
Dim ColName As String
Dim BlankCol As Integer
Dim Source As Range
Dim SourceCol As String
Dim SourceAdd As String
Dim FirstColName As String
BlankCol = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column + 1
FirstCol = BlankCol + 1
Cells(1, FirstCol).Value = "FirstCol"
FirstColName = Cells(1, FirstCol).Value
Cells(1, BlankCol).Value = "Unique Classes"
Set Source = ActiveSheet.Rows(1).Find("International", LookIn:=xlValues)
SourceCol = Source.Column
SourceAdd = Source.Address
Range(SourceAdd).EntireColumn.TextToColumns _
Destination:=Range("PatBase[[#Headers], [" & FirstColName & "]]"), _
DataType:=xlDelimited, _
Tab:=True, Other:=True, OtherChar:="" & Chr(10) & "",_
FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1), Array(4, 1), Array(5, _
1), Array(6, 1), Array(7, 1), Array(8, 1), Array(9, 1), Array(10, 1), Array(11, 1), _
Array(12, 1), Array(13, 1), Array(14, 1)), _
TrailingMinusNumbers:=True
Once the data is in the columns I then have more code which truncates it to 4 characters with the range in the same format, but this is working fine:
CurrentCol = FirstCol
For i = FirstCol To LastCol
Columns(CurrentCol).Select
ColName = Cells(1, CurrentCol).Value
If ColName = "" Then
Exit For
End If
Selection.TextToColumns Destination:=Range("PatBase[[#Headers], [" & ColName & "]]"), _
DataType:=xlFixedWidth, FieldInfo:=Array(Array(0, 1), Array(4, 9)), _
TrailingMinusNumbers:=True
CurrentCol = CurrentCol + 1
Next i
I suspect I am missing something obvious but I'm not a skilled macro writer so am at a loss. Can anyone help?
I wrote VBA code that opens all of the .xls files in a folder, and copies and pastes desired information out of those files into a new workbook.
Each row in the new workbook is associated with a file from the folder.
Column1, Column2, Column3
FileName1, ABC, XYZ
FileName2, DEF, TUV
The info in Column3 has the formatting of
ArbitraryString1(Very_Important_Info)ArbitraryString2
Because I wanted Column3 to look nice, I iterated over every row and used
Range("C"&X).TextToColumns DataType:=xlDelimited, Other:=True _
OtherChar:="("
Columns("E:E").Insert Shift:=xlToRight *
Range("D"&X).TextToColumn DataType:=xlDelimited, Other:=True _
OtherChar:=")"
Range("C"&X).TextToColumns DataType:=xlDelimited, Other:=True _
OtherChar:="(" **
Columns("E:Z").Delete
Columns("C:C").Delete
*This is needed so when I call TextToColumn the second time I do not get a message asking if I want to overwrite what is already in that column.
I end up with
Column1, Column2, Column3
FileName1, ABC, Very_Important_Info_1
FileName2, DEF, Very_Important_Info_2
After calling OtherChar:="(" the first time I end up seeing
(Very_Important_Info)ArbitraryString2
with the left bracket still attached.
I call the method a second time or ColumnC would look like
(Very_Important_Info
Might work better with SPLIT
Sub TextToCols()
Dim rng As Range
Dim r As Range
Dim l As Long
Dim arr As Variant
With ActiveSheet
l = .Cells(.Rows.Count, "C").End(xlUp).Row
Set rng = Range("C2:C" & l)
For Each r In rng
r.Value = Application.WorksheetFunction.Substitute(r.Value, ")", "(")
arr = Split(r.Value, "(")
Cells(r.Row, 3).Value = arr(1)
Next r
End With
End Sub
Or text-to-columns:
Sub TextToCols()
Dim rng As Range
Dim r As Range
Dim l As Long
With ActiveSheet
l = .Cells(.Rows.Count, "C").End(xlUp).Row
Set rng = Range("C2:C" & l)
For Each r In rng
r.Value = Application.WorksheetFunction.Substitute(r.Value, ")", "(")
Next r
With .UsedRange.Columns("C").Cells
.TextToColumns Destination:=Range("C1"), _
DataType:=xlDelimited, _
OtherChar:="("
End With
End With
End Sub
Here is a simplified version of Michal Rosa's code:
Sub BeautifyIt()
With Worksheets("Sheet1")
With .Range("C2", .Range("C" & .Rows.Count).End(xlUp))
.Replace ")", "("
.TextToColumns Destination:=.Cells(1, 1), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=True, _
OtherChar:="(", FieldInfo:=Array(Array(1, 1), Array(2, 1)), TrailingMinusNumbers:=True
End With
End With
End Sub
I have a csv with a "|"-delimeter, so I open the workbook:
Set wb = Workbooks.Open(xl_newest_export)
Set ws = wb.Sheets(1)
and use texttocolumns:
ws.Range("A1:A" & CStr(lastRow)).TextToColumns Destination:=Range("A1:A" & CStr(lastRow)), DataType:=xlDelimited, _
TextQualifier:=xlNone, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=False, Comma:=False, Space:=False, DecimalSeparator:=".", Other:=True, OtherChar _
:="|"
However this fails as the text gets evaluated by Excel - a few doubles are getting converted to date. e.g.
"1" -> "01.01.1900"
How can I achieve the above with no Evaluation?
Edit:
As suggested in the comments - Fieldinfo is the solution. However I tried to build a Array-string... e.g. "Array(Array(3,1)...)" but this fails too..
Once you have filled column A with data, use this instead:
Sub PiedPipper()
Dim rng As Range, r As Range, pipe As String
Cells.NumberFormat = "#"
Set rng = Range("A1:A" & Cells(Rows.Count, "A").End(xlUp).Row)
pipe = "|"
For Each r In rng
ary = Split(r.Value, pipe)
r.Resize(1, UBound(ary) + 1) = ary
Next r
End Sub
EDIT#1:
Use this to get the .csv data into column A:
Sub GetCVSData()
Dim FilesToOpen
Dim wf As WorksheetFunction
Set wf = Application.WorksheetFunction
Dim ary, bry, DQ As String
DQ = Chr(34)
FilesToOpen = Application.GetOpenFilename _
(FileFilter:="Text Files (*.csv), *.csv", Title:="Text Files to Open")
Close #1
Open FilesToOpen For Input As #1
j = 1
Do While Not EOF(1)
Line Input #1, TextLine
With Cells(j, 1)
.NumberFormat = "#"
.Value = TextLine
End With
j = j + 1
Loop
Close #1
End Sub
basically i am using the TextToColumns function to separate out data separated by a semi colon in the same cell. problem is there are 2 columns of data that needs this function done and i have to insert the data without overwriting.
(go easy, first time with VBA and excel) this is what i currently have:
Sub Button1_Click()
Dim rng As Range
Dim sh As Worksheet
Set sh = Worksheets("Sheet1")
With sh
Set rng = .[Q1]
Set rng = .Range(rng, .Cells(.Rows.Count, rng.Column).End(xlUp))
num = Application.WorksheetFunction.Max(Columns("P"))
rng.Offset(0, 1).Resize(1, num).EntireColumn.Insert
rng.TextToColumns Destination:=rng, DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=True, Comma:=False, Space:=False, Other:=False, _
FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
End With
Set sh2 = Worksheets("Sheet1")
With sh2
num2 = Application.WorksheetFunction.Max(Columns("P"))
Dim lastColumn As Integer
lastColumn = ActiveSheet.UsedRange.Column - 1 + ActiveSheet.UsedRange.Columns.Count
MsgBox Replace(Cells(1, lastColumn).Address(False, False), "1", "")
MsgBox lastColumn
Set rng = .[W1]
Set rng = .Range(rng, .Cells(.Rows.Count, rng.Column).End(xlUp))
rng.TextToColumns Destination:=rng, DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=True, Comma:=False, Space:=False, Other:=False, _
FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
End With
End Sub
ok so what i am trying to fix is setting the rng manually in the second part to W1. the rng needs to be the next empty column. so lastColumn using the MsgBox DOES return the column "W" but i cannot set that to rng (type mismatch). oh and the num variable is set to the amount of columns i need to insert. my data looks like this:
count | column with ; data need separating | column with ; data need separating
5 | 5 sets of data separated by semi colons | don't care because this is the end of sheet
is there any easier way to do this? am i even close?
... Easiest solution if I understand your question correctly... Why don't you just make a THIRD column that equals Column1 & ";" & Column2, then just do text-to-columns on that single column??
Or am I missing something??
Assuming I'm understanding your setup correctly, the following code should work.
If you process the data columns from right to left, you don't have to worry about the change in address references when the columns are inserted. That means you can use a single block of insertion/conversion code, iterated over the two data address references, which I've assumed are Q1 and R1.
Note also that I added an offset to the TextToColumns destination to avoid overwriting the original data.
Option Explicit
Sub myTextToColumns()
Dim sh As Worksheet
Dim rng As Range
Dim num As Long
Dim arr As Variant
Dim i As Long
Set sh = Worksheets("Sheet1")
arr = Array("R1", "Q1")
num = Application.WorksheetFunction.Max(Columns("P"))
With sh
For i = LBound(arr) To UBound(arr)
Set rng = .Range(arr(i))
Set rng = .Range(rng, .Cells(.Rows.Count, rng.Column).End(xlUp))
rng.Offset(0, 1).Resize(1, num).EntireColumn.Insert
rng.TextToColumns Destination:=rng.Offset(0, 1), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, _
Semicolon:=True, Comma:=False, Space:=False, Other:=False, _
FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), TrailingMinusNumbers:=True
Next
End With
End Sub