So, in a workbook I have a lot of sheets from which I want to use texttocolumns for a Date, the date is usually something like "11/22/2018 10:59:59 AM" and I only want it to do a MDY with a delimited text to columns. The delimiter must be false.
Sub LoopCertain() 'Excel VBA to exclude sheets
'SP Edit, error handler
On Error Goto errHandler
If False Then
errHandler:
MsgBox Err.Description
'This will cause the routine to carry on where it left off
Resume Next
End If
'SP End of Edit
Dim ws As Worksheet
Dim objRange1 As Range
Dim objRange2 As Range
For Each ws In ActiveWorkbook.Worksheets
Select Case ws.Name
Case Is = "General", "Verification", "OEM Plant Summary"
'No Code here if excluded
Case Else
'Set up the ranges
Set objRange1 = Range("C:C")
Set objRange2 = Range("I:I")
Set ws = ActiveSheet
'Do the first parse
objRange1.TextToColumns _
Destination:=Range("C1"), _
DataType:=xlDelimited, _
Tab:=False, _
Semicolon:=False, _
Comma:=False, _
Space:=False, _
Other:=False, _
OtherChar:="-"
'Do the second parse
objRange2.TextToColumns _
Destination:=Range("I1"), _
DataType:=xlDelimited, _
Tab:=False, _
Semicolon:=False, _
Comma:=False, _
Space:=False, _
Other:=False, _
OtherChar:="-"
End Select
Next ws
End Sub
I get errors when trying to run this. I need to change Columns "I" and "C" and results must be in the same column. Appreaciate if you can help since I have been like the whole week trying different types of loops and nothing works. This one work if I remove the Loop though...
Here is the sample data:
A fixed width would probably be more appropriate. Your sample data leaves some unanswered questions but I'll assume a mmddyyyy (not mdyyyy) date format and data that either starts in row 1 or has a header label in row 1 with 10 or less characters.
For Each ws In ActiveWorkbook.Worksheets
Select Case ws.Name
Case "General", "Verification", "OEM Plant Summary"
'No Code here if excluded
Case Else
With ws.Range("C:C")
.TextToColumns Destination:=.Cells(1), DataType:=xlFixedWidth, _
FieldInfo:=Array(Array(0, xlMDYFormat), Array(10, xlSkipColumn))
End With
With ws.Range("I:I")
.TextToColumns Destination:=.Cells(1), DataType:=xlFixedWidth, _
FieldInfo:=Array(Array(0, xlMDYFormat), Array(10, xlSkipColumn))
End With
End Select
Next ws
Why do you need to use TextToColumns? I would be tempted to convert the text to a proper date (meaning a date serial number) and then format the column in whichever way you want to display the date. The advantage of this method would be that you can actually retain the time value contained in the date if case you want to know it later but without displaying it.
However, since you are intending to manipulate the text I think the code below is more efficient. Please try it.
Sub ReformatDate()
Const FirstDataRow As Long = 1 ' change as appropriate
Dim Ws As Worksheet
Dim Rng As Range
Dim Arr As Variant
Dim C As Long
Dim i As Long
For Each Ws In Worksheets
If InStr(1, ",General,Verification,OEM Plant Summary", "," & Ws.Name, _
vbTextCompare) = 0 Then
With Ws
For C = 3 To 9 Step (9 - 3) ' columns C & I
Set Rng = .Range(.Cells(FirstDataRow, C), _
.Cells(.Rows.Count, C).End(xlUp))
Arr = Rng.Value
For i = 1 To UBound(Arr)
If Len(Arr(i, 1)) Then Arr(i, 1) = Split(Arr(i, 1))(0)
Next i
Rng.Value = Arr
.Columns(C).AutoFit
Next C
End With
Next Ws
End Sub
Related
I am making a macro that Optimizes the sheet by deleting unused ranges that create very large file sizes. It does this by finding the last used row (column), selecting a range from that last used row (column) to the very bottom-right) of the sheet, and clearing formats and deleting those cells, to delete the unused range that is taking up space.
E.g. if last used row is 50, select range A50 to Bottom right of sheet (aka XFD104873, clear those formats and delete range
I have been able to do this with rows, but not with columns. In the below code, I get a syntax error (shown as 'SYNTAX ERROR' below) when case 2 runs, and I can't for the life of me figure out why.
I need to use R1C1 notation but for some reason the range(cells(#,#)) aren't picking it up properly.
I think it has to do with the second part in which I do range(cells(#,#)).End(xlDown).end(Toright)
Let me know if i can provide any additional information!
Nick
'Option Explicit
Sub Optimize()
'Call OptimizeSheet(1, "HR_Data")
Call OptimizeSheet(2, "DomesticAsset_Data")
'Call OptimizeSheet(3, "InternationalAsset_Data")
End Sub
Sub OptimizeSheet(ByVal choice As Long, ByVal sht As String)
' 1 = Rows
' 2 = Columns
' 3 = Both
If WorksheetExists(sht) = False Then
MsgBox "Worksheet doesn't exist, check macro code"
Exit Sub
End If
'Workbook
Dim wb As Workbook
'Last Row and Column Variables
Dim lr As Long
Dim lc As Long
'File Size variables
Dim aFileSize As Long
Dim bFileSize As Long
Dim chngFileSize As Long
Set wb = Application.ActiveWorkbook
On Error GoTo errHandler
'Get file size before optimizing
aFileSize = FileLen(Application.ActiveWorkbook.FullName)
Select Case choice
'Rows
Case 1:
lr = Worksheets(sht).Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
With Worksheets(sht).Range("A" & lr, Range("A" & lr).End(xlDown).End(xlToRight))
.ClearFormats
.Delete
End With
'Columns
Case 2:
lc = Worksheets(sht).Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
SYNTAX ERROR HERE
With Worksheets(sht).Range(Cells(1, lc), RangeCells(1, lc).End(xlDown).End(xlToRight))
.ClearFormats
.Delete
End With
'Both
Case 3:
lr = Worksheets(sht).Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
With Worksheets(sht).Range("A" & lr, Range("A" & lr).End(xlDown).End(xlToRight))
.ClearFormats
.Delete
End With
'chnge
lc = Worksheets(sht).Cells.Find(What:="*", _
After:=Range("A1"), _
LookAt:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
With Worksheets(sht).Range(Cells(1, lc).Address(), Range(Cells(1, lc).Address()).End(xlDown).End(xlToRight))
.ClearFormats
.Delete
End With
Case Else:
MsgBox "Wrong Choice, check macro code"
End Select
Application.ThisWorkbook.Save
bFileSize = FileLen(Application.ActiveWorkbook.FullName)
If aFileSize + bFileSize = 0 Then
MsgBox "error in filesize"
End If
chngFileSize = bFileSize - aFileSize
If chngFileSize = 0 Then
MsgBox (sht & " already optimized")
Else
MsgBox ("Done. " & (chngFileSize / 1000) & "MB Saved")
End If
Exit Sub
errHandler:
MsgBox "error on line" & Erl
End Sub
Function WorksheetExists(shtName As String, Optional wb As Workbook) As
Boolean
Dim sht As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
On Error Resume Next
Set sht = wb.Sheets(shtName)
On Error GoTo 0
WorksheetExists = Not sht Is Nothing
End Function
To delete columns:
With Worksheets(sht)
.Range(.Cells(1, lc + 1), _
.Cells(1, lc +1 ).End(xlToRight)).EntireColumn.Delete
End With
I am a little new to VBA
How the macro works is when someone inputs in the error child_variations.color: Update attribution to reflect the correct data or more than 1 of these errors into a cell. The macro will split in the string at the colon into separate cells (that part of the macro is working correctly). Then the macro needs to loop through each cell and if the string in the cell contains an underscore () then that string is saved in a variable and is put into a cell. If the string does not contain an underscore (), then it is saved into a different variable.
The issue that I am having is putting the string together into separate cells. I want to put all of the text that is on the left of the colon into one string and one cell. I also want to put the text that is right of the colon in another string and cell. I have tried to use the loop and the if statements below, but all of the text to the left and right of the colon is being put into the same cell.
Below I have before along with how the cells are supposed to look in the spreadsheet.
Before
child_variations.color:Update attribution to reflect the correct data.
digital_assets.images.primary_image_url:Primary image does not align with alternate image(s).
How it should look
child_variations.color Update attribution to reflect the correct data.
Any help that you can give to me would help out greatly!
Sub delimted()
Dim ws As Worksheet
Dim cel As range
Dim str As String
Dim str_is_blank As String
Dim my_range As range
Dim no_of_rows As Long
Dim i As Long
Dim str_with_special_char As String
Set my_range = Sheets("Setup").range("L7:Z500")
no_of_rows = my_range.Rows.Count
Set ws = ThisWorkbook.Sheets("Setup")
ws.range("I7:I500").Select
Selection.TextToColumns _
Destination:=range("L7:L500"), _
DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=True, _
Semicolon:=False, _
comma:=False, _
Space:=True, _
Other:=True, _
OtherChar:=":"
For Each cel In my_range.Cells
If InStr(cel.Value, "_") > 0 Then
str_with_special_char = str_with_special_char & " " & cel.Value
range("I7").Value = str_with_special_char
ElseIf Not InStr(cel.Value, "_") Then
str = str & " " & cel.Value
range("J7").Value = str
ElseIf IsEmpty(cel.Value) Then
str_is_blank = str_is_blank & cel.Value
End If
Next cel
End Sub
first of all can you show a column with your data and a column with the desired result so I can make a try?
Second:
ws.range("I7:I500").Select
will slow down your macro, instead you can use:
ws.range("I7:I500").TextToColumns _
Destination:=range("L7:L500"), _
DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, _
ConsecutiveDelimiter:=False, _
Tab:=True, _
Semicolon:=False, _
comma:=False, _
Space:=True, _
Other:=True, _
OtherChar:=":"
But anyway if you want to put some words with "_" in a range and other in another range you can use a loop, it is more easy to do and understand.
For example if you want to split the words with "_" then you can use something like this
Dim cell As Range
For Each cell In Range("L7:L500").Cells
If InStr(cell, "_") > 0 Then
cell.Offset(0, 1) = Left(cell, WorksheetFunction.Find("_", cell))
cell.Offset(0, 2) = Right(cell, Len(cell) -WorksheetFunction.Find("_",cell))
Else
cell.Offset(0, 3) = cell
End If
Next cell
and if we suppose that the column L is with a word like "Hello_World" then in the column M you will have "Hello_" and in the column N you will have "World", the next column will have all those words that dont have any "_"
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 am trying to accelerate my Excel VB Macro.
I have tried the 5 alternatives below.
But I wonder if I could shorten the execution further.
I found 2 alternatives in User Blogs which I could not get to work.
One alternative is also found in a User Blog but do not understand.
Sub AccelerateMacro()
'
' v1 052817 by eb+mb
' Macro to copy as fast as possible sheet from one workbook into another workbooks
' Declarations for variables are not shown to make code example more legible
' Macro is stored in and run from "DestinationWorkBook.xlsm"
StartTime = Timer
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Alternative = "First"
If Alternative = "First" Then
Workbooks.Open Filename:="SourceWorkBook.xls"
Cells.Select
Selection.Copy
Windows("DestinationWorkBook.xlsm").Activate
Sheets("DestinationSheet").Select
Range("A1").Select
ActiveSheet.Paste
Windows("SourceWorkBook.xls").Activate
ActiveWorkbook.Close
End If
If Alternative = "Second" Then
Workbooks.Open Filename:="SourceWorkBook.xls", ReadOnly:=True
Cells.Select
Selection.Copy
Windows("DestinationWorkBook.xlsm").Activate
Sheets("DestinationSheet").Select
Range("A1").Select
ActiveSheet.Paste
Workbooks("SourceWorkBook.xls").Close SaveChanges:=False
End If
If Alternative = "Third" Then
' I could not get this alternative to work
Workbooks.Open("SourceWorkBook.xls").Worksheets("SourceSheet").Copy
Workbooks.Open("DestinationWorkBook.xlsm").Worksheets("DestinationSheet").Range("A1").PasteSpecial
End If
If Alternative = "Fourth" Then
' I could not get this alternative to work
Workbooks.Open("DestinationWorkBook.xlsm").Worksheets("DestinationSheet").Range("A1") = Workbooks.Open("SourceWorkBook.xls").Worksheets("SourceSheet")
End If
If Alternative = "Fifth" Then
' I don't understand the code in this alternative
Dim wbIn As Workbook
Dim wbOut As Workbook
Dim rSource As Range
Dim rDest As Range
Set wbOut = Application.Workbooks.Open("DestinationWorkBook.xlsm")
Set wbIn = Application.Workbooks.Open("SourceWorkBook.xls")
With wbIn.Sheets("SourceSheet").UsedRange
wbOut.Sheets("DestinationSheet").Range("A1").Resize(.Rows.Count, .Columns.Count) = .Value
End With
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
End Sub
Instead of using UsedRange, find the actual Last Row and Last Column and use that range. UsedRange may not be the range that you think it is :). You may want to see THIS for an explanation.
See this example (UNTESTED)
Sub Sample()
Dim wbIn As Workbook, wbOut As Workbook
Dim rSource As Range
Dim lRow As Long, LCol As Long
Dim LastCol As String
Set wbOut = Workbooks.Open("DestinationWorkBook.xlsm")
Set wbIn = Workbooks.Open("SourceWorkBook.xls")
With wbIn.Sheets("SourceSheet")
'~~> Find Last Row
lRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
'~~> Find Last Column
LCol = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
'~~> Column Number to Column Name
LastCol = Split(Cells(, LCol).Address, "$")(1)
'~~> This is the range you want
Set rSource = .Range("A1:" & LastCol & lRow)
'~~> Get the values across
wbOut.Sheets("DestinationSheet").Range("A1:" & LastCol & lRow).Value = _
rSource.Value
End With
End Sub
I have columns of numbers that, for whatever reason, are formatted as text. This prevents me from using arithmetic functions such as the subtotal function. What is the best way to convert these "text numbers" to true numbers?
Here is a screenshot of the specific issue:
I've tried these snippets to no avail:
Columns(5).NumberFormat = "0"
and
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Use the below function (changing [E:E] to the appropriate range for your needs) to circumvent this issue (or change to any other format such as "mm/dd/yyyy"):
[E:E].Select
With Selection
.NumberFormat = "General"
.Value = .Value
End With
P.S. In my experience, this VBA solution works SIGNIFICANTLY faster on large data sets and is less likely to crash Excel than using the 'warning box' method.
I had this problem earlier and this was my solution.
With Worksheets("Sheet1").Columns(5)
.NumberFormat = "0"
.Value = .Value
End With
This can be used to find all the numeric values (even those formatted as text) in a sheet and convert them to single (CSng function).
For Each r In Sheets("Sheet1").UsedRange.SpecialCells(xlCellTypeConstants)
If IsNumeric(r) Then
r.Value = CSng(r.Value)
r.NumberFormat = "0.00"
End If
Next
This converts all text in columns of an Excel Workbook to numbers.
Sub ConvertTextToNumbers()
Dim wBook As Workbook
Dim LastRow As Long, LastCol As Long
Dim Rangetemp As Range
'Enter here the path of your workbook
Set wBook = Workbooks.Open("yourWorkbook")
LastRow = Cells.Find(What:="*", After:=Range("A1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastCol = Cells.Find(What:="*", After:=Range("A1"), SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
For c = 1 To LastCol
Set Rangetemp = Cells(c).EntireColumn
Rangetemp.TextToColumns DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _
:=Array(1, 1), TrailingMinusNumbers:=True
Next c
End Sub
''Convert text to Number with ZERO Digits and Number convert ZERO Digits
Sub ZERO_DIGIT()
On Error Resume Next
Dim rSelection As Range
Set rSelection = rSelection
rSelection.Select
With Selection
Selection.NumberFormat = "General"
.Value = .Value
End With
rSelection.Select
Selection.NumberFormat = "0"
Set rSelection = Nothing
End Sub
''Convert text to Number with TWO Digits and Number convert TWO Digits
Sub TWO_DIGIT()
On Error Resume Next
Dim rSelection As Range
Set rSelection = rSelection
rSelection.Select
With Selection
Selection.NumberFormat = "General"
.Value = .Value
End With
rSelection.Select
Selection.NumberFormat = "0.00"
Set rSelection = Nothing
End Sub
''Convert text to Number with SIX Digits and Number convert SIX Digits
Sub SIX_DIGIT()
On Error Resume Next
Dim rSelection As Range
Set rSelection = rSelection
rSelection.Select
With Selection
Selection.NumberFormat = "General"
.Value = .Value
End With
rSelection.Select
Selection.NumberFormat = "0.000000"
Set rSelection = Nothing
End Sub
The solution that for me works is:
For Each xCell In Selection
xCell.Value = CDec(xCell.Value)
Next xCell
Using aLearningLady's answer above, you can make your selection range dynamic by looking for the last row with data in it instead of just selecting the entire column.
The below code worked for me.
Dim lastrow as Integer
lastrow = Cells(Rows.Count, 2).End(xlUp).Row
Range("C2:C" & lastrow).Select
With Selection
.NumberFormat = "General"
.Value = .Value
End With
The solution that worked for me many times is:
Sub ConvertTextToNumber()
With Range("A1:CX500") 'you can change the range
.NumberFormat = "General"
.Value = .Value
End With
End Sub
For large datasets a faster solution is required.
Making use of 'Text to Columns' functionality provides a fast solution.
Example based on column F, starting range at 25 to LastRow
Sub ConvTxt2Nr()
Dim SelectR As Range
Dim sht As Worksheet
Dim LastRow As Long
Set sht = ThisWorkbook.Sheets("DumpDB")
LastRow = sht.Cells(sht.Rows.Count, "F").End(xlUp).Row
Set SelectR = ThisWorkbook.Sheets("DumpDB").Range("F25:F" & LastRow)
SelectR.TextToColumns Destination:=Range("F25"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _
:=Array(1, 1), TrailingMinusNumbers:=True
End Sub
From the recorded macro one gets the code below; for a new application you just need to update selection and range:
Sub num()
Columns("B:B").Select
Selection.TextToColumns Destination:=Range("B1"), DataType:=xlDelimited, _
TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _
:=Array(1, 1), TrailingMinusNumbers:=True
End Sub
I had problems making above codes work. To me multiplying with 1 did the trick:-)
Cells(1, 1).Select
Cells(1, 1) = ActiveCell * 1