Paste into Excel without Excel's "intelligent" converting with VBA [closed] - excel

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I have to paste data from several sources into Excel on daily basis. The usual way is that you paste the data, then start the text conversion wizzard (translated from german) and make several settings for the delimiter and for the columns. You have to do this, because Excel assumes that 3.4 has to be a date-Format or anything starting with + must be a formula. But in most cases it is not! So I have to pick the columns and set the format from standard to text. Additional, in Germany we do not write 1,223,443.44€ but we write 1.223.443,44€, so each time I have to make this setting also in the wizzard.
So: I want this done with VBA. What I have tried so far:
Somehow execute the text conversion wizzard via VBA. But the macro recorder does not record it properly.
Selection.TextToColumns: Works fine but the pasted text mus be in one column. When text ist for example tab-delimited, Excel automatically puts it in many columns.
Insert in many columns and then by vba collect into one column to use (2). Does not work because at this point the data is already damaged.
The desired behavior is that i can specify the delimiter already before pasting the data in a user friendly dialog, and then paste all data without any poor attempts of excel to interpret it as numbers, formulas, date/time or anything else.
Furthermore I want it to be able to choose number format as 1.000,0 or 1,000.0 in a user friendly dialog, but htis part can also be done after pastinng the data, as long as excel does not already destroy the data with its format assumptions.
Example Data to paste can be:
Part_Number Version Quantity
+213324443 2.3 1,000.00
AZ38643892 1.0 71.11
11.1.89 7.2 0.03
which shows that the + would be interpreted as formula, the version probably as a date and the Quantity at least in german excel would not be the correct numbers.

You can read the content directly from the clipboard using DataObject, but wou would need to figure out exactly what format you wanted for each "column" in that data, and it would also require you to be able to specify the delimiter.
Here's a super-basic example:
Sub tester()
Dim MyData As New DataObject, arrLines, arrVals, txt, ln, v, c As Range
Set c = ActiveCell
'get the content from the clipboard
MyData.GetFromClipboard
txt = MyData.GetText
arrLines = Split(txt, vbCrLf) 'split to lines
For ln = 0 To UBound(arrLines) 'loop array of lines
arrVals = Split(arrLines(ln), vbTab) 'split to values
For v = 0 To UBound(arrVals) 'loop all values in this line
With c.Offset(ln, v)
.NumberFormat = "#" 'eg. setting all value cells to "Text" format
.Value = arrVals(v) 'populate the value
End With
Next v
Next ln
End Sub

Related

Display a checkmark for any value

Using the cell format Excel allows any value to be displayed as any predetermined character. For many years I have used this feature to display a checkmark but now the code below is giving me a headache.
With Rng
.HorizontalAlignment = xlHAlignCenter
.NumberFormat = """" & ChrW(252) & """"
With .Font
.Name = "Wingdings"
.Bold = True
End With
End With
Everything is in the same workbook:
There is an account, a journal of sorts. My code filters out entries for one subject and writes the result to a dedicated sheet. The account has a column with checkmarks of this type and they are copied correctly to the tab with the filtered data. From the filtered extract my code copies items into a third tab where the info is displayed in context. Data, values only, are transferred via an array. As a result of this method the destination tab receives and displays the cell values. The above code intends to format the affected cells to show a checkmark.
Everything works fine except that the font doesn't appear to be applied. The formatted cells do show Wingdings as applied font. The value is present and suppressed but instead of a checkmark it displays nothing.
The cell format is set correctly. Since it was present in the workbook before it's noteworthy that no new format was added. (The use of ChrW() is a legacy from a problem in forgotten years past. Chr() produces the same result in the circumstance.) I tried to set the font before or after the NumberFormat.
I found that my present version of Excel (365) doesn't seem to have a checkmark in its Wingdings. Surprise because it's there in the same workbook but I didn't find it in Symbols. Instead I found Chr(80) in Wingsdings2. Applied with the same code the cells display "P", with Wingsdings2 shown as applied font.
Of course I checked the formatting of similar cells in the account and the filtered copy minutely and discovered no difference. I also tried to format the final cells again, using the same settings, but they stubbornly look at me with a blank stare.
As a coup de grace I applied the same code above to the ActiveCell on a blank sheet in the same workbook and it worked beautifully, Bold and all. So, what might be different on the worksheet on which it doesn't work? Actually, that is my question here.
Rows are inserted one by one, filled cell by cell, and a different format applied to each before the value is written. But stepping through the code with F8 produced no revelations. I also tried to enable ScreenUpdating (normally turned off while the code runs) but no different result. So, why isn't the specified font applied correctly?
The cells do have two peculiarities. One is that they are the last ones in the row. The other is that all other cells in the row are merged. This leads to a Merge command being applied to the single cell. To show the measure of my desperation I added If Rng.Cells.Count > 1 Then Rng.Merge. Of course, it made no difference.

Prevent # signs in formulas [duplicate]

This question already has an answer here:
Excel VBA - How to add dynamic array formula
(1 answer)
Closed 2 years ago.
I was playing around with Excel to try and help out a friend with a problem, and wrote the following macro
Sub test()
Worksheets("Sheet3").Cells(1, 4) = "=SUM(A1:A2)"
End Sub
The idea was to try and figure out if I could create a macro that writes formulas in a specific cell (which we know we could) but also be able to change the range of the formula.
For example, if instead of just 2 values to sum up, I had 4 values, we want the macro to the able to count all the values and then set a range for all the formulas.
The problem here is that when I write the piece of code shown above, for some reason in the cell it appears " =#SUM(A1:A2) ". I have no idea what the "#" symbol is supposed to do nor why it is showing up. As a result though, I get a "name?" error and the function doesn't work. However, if I manually delete the "#" symbol, it works perfectly.
Can anyone explain why the "#" symbol is showing up and how not make it show up ?
This should work :)
As the .Formula is made for excel to recognize that you want to print a formula.
Worksheets("Sheet3").Cells(1, 4).Formula = "=SUM(A1:A2)"

I need to Concatenate the values and separate with "|" but ignore blanks

I should start by saying I'm new at this, but I've been asked to get something done at work. I'm using Excel 2008 on a Mac.
I've created a data set that is roughly 3000 rows x 95 columns. the first column is a concatenation of product descriptions, manufacturers, etc. The rows are a list of keywords that I've used the following formula to identify and display in each of the 3000 rows:
=IF(ISNUMBER(SEARCH(C$3,$A3)),C$2,"") .
This has left me with data scattered throughout the sheet. I now need to combine the data from each row into one cell, with each discovered keyword separated by |, but I need to ignore blank cells so that I have a result like the following:
Keyword1|Keyword3|Keyword4|
and not like this:
Keyword1||Keyword3|Keyword4||||||||||||
Anyone have any ideas?
Thanks
You could use & like this:
="keyword1"&"|"&"keyword2"&... which does not skip blank cells
or if keyword1 is in cell A1 and keyword 2 in B1 then
=IF(OR(A1="",B1=""),"",A1&"|"&B1)
which will leave the result blank if either A1 or B1 are blank
I ran into this years ago when I was trying to create lists of potential racing picks from a list of horses in a race. I never found something I liked, but used several different methods as I changed my preferences over time. Here is one somewhat generic solution:
=SUBSTITUTE(SUBSTITUTE(TRIM(SUBSTITUTE(SUBSTITUTE(A7&"|"&B7&"|"&...&DM7," ","~"),"|"," "))," ","|"),"~"," ")
where the series starting with A7 and ending with DM7 would be replaced with the concatenation you have with multiple "|" symbols.
The formula looks for existing spaces and replaces them with an unused character (in this case, I used a "~"), then it replaces "|" with a " " and uses the TRIM command to eliminate leading and ending spaces as well as excessive spaces in between. Then it replaces the remaining spaces with "|" and puts back the initial spaces by substituting a space for any "~".
Obviously, this is a bit simpler if your keywords have no spaces, but that was not stated.
Addendum....
Thinking about this last night, I think getting to one concatenated string based on 3000 rows of data with up to 95 columns may be impossible. This is likely to easily run up against the string limit size of 32,767 since if even 5% of those cells have just a single character, you will have 14,250 characters plus a nearly equal amount of separators. I do not see how you would do this using the technique I posted. You could use this technique on a row by row basis and then cut and paste these to a plain text file, but I am beginning to think a native Excel solution would be nearly impossible, especially without VBA which we could have used to write the text out.
While my earlier suggestion might work well for relatively small ranges, it will not work for data approaching the size of the original request. Excel 2008 on a Mac will not likely be able to handle this, but if you have access to a version of Excel that can use VBA, this suggestion may help you since it uses the extended capabilities of VBA and will put the concatenated data into a text file rather than trying to leave it in the spreadsheet.
I am still trying to figure out a way to do this without using a string or VBA.
I am including some step-by-step information in case it is useful to you or others.
Open the spreadsheet with the 95 rows and 3000 columns of data.
Open the Visual Basic Editor and Choose Insert / Module from the menu.
Paste the following code into the editor window:
Option Explicit
Function ConcatNonblankWithSeparator(rngRange As Range, strSeparator As String) As String
Dim rngCell As Range
Dim strReturn As String
For Each rngCell In rngRange
' MsgBox rngCell.Address
If Len(rngCell.Value) > 0 Then
' MsgBox "before: " & strReturn
strReturn = strReturn & rngCell.Value & strSeparator
' MsgBox "after: " & strReturn
End If
Next rngCell
' MsgBox strReturn
' MsgBox Len(strReturn)
' MsgBox Len(strSeparator)
ConcatNonblankWithSeparator = Left(strReturn, Len(strReturn) - Len(strSeparator))
End Function
Sub ConcatRange()
Dim rngCell As Range
Dim strSeparator As String
Dim strFileName As String
strFileName = Application.DefaultFilePath & "\TestDelimOutput.txt"
Set rngCell = Sheets("Data").Range("A1:DX3000")
strSeparator = "|"
Open strFileName For Output As #1
Write #1, ConcatNonblankWithSeparator(rngCell, strSeparator)
Close #1
End Sub
The first line protects you (or more likely me) from not defining variables before using them.
The Function creates a fairly generic concatenation routine that takes a range and a string and creates a returned string with nonblank values within the range concatenated and separated by the string. The msgbox commands can be uncommented (by removing the ' at the start of the line) if you want to see what is going on. The "MsgBox strReturn" will unlikely display the full amount of the concatenated data due to size limitations of that function, but may during testing.
The Sub actually makes the specific identification of the range to be processed and identifies the separator to be used. It writes the result to a test file. If you want a different separator (perhaps a " | " rather than a "|" you would specify it here. If you want a different sheet name, you would replace "Data" with the name of your sheet (in quotes). If you have a different range, you would replace the "A1:DX3000" with your range (also in quotes). If you want to use a different file name, you would specify that in the strFileName variable (along with a path to the location you want to use).
I am a bit of a hacker when it comes to VBA, so someone may suggest some stylistic or technical improvements, but this should get you started. I did create a 700,000 byte file with this, so it will handle a lot of data.
I hope this points you in a better direction than my earlier post.
What I tried next were some manual steps. I tried using a Macintosh CSV file but could not work with it because I was having trouble interpreting the end-of-line characters, so I settled for allowing Excel to create an MS-DOS text file in this process. Your actual process may need to be adapted to your environment. I used MS Word instead of Notepad or Notepad++ in the hopes that Microsoft has already adapted their search/replace functionality to the MAC.
With the data in a sheet called "Data" in columns A1..DX3000, I created a second sheet with the following formula in A1:
=SUBSTITUTE(TRIM(SUBSTITUTE(SUBSTITUTE(Data!A1&","&Data!B1&","&Data!C1&","&Data!D1&","&Data!E1&","&Data!F1&","&Data!G1&","&Data!H1&","&Data!I1&","&Data!J1&","&Data!K1&","&Data!L1&","&Data!M1&","&Data!N1&","&Data!O1&","&Data!P1&","&Data!Q1&","&Data!R1&","&Data!S1&","&Data!T1&","&Data!U1&","&Data!V1&","&Data!W1&","&Data!X1&","&Data!Y1&","&Data!Z1&","&Data!AA1&","&Data!AB1&","&Data!AC1&","&Data!AD1&","&Data!AE1&","&Data!AF1&","&Data!AG1&","&Data!AH1&","&Data!AI1&","&Data!AJ1&","&Data!AK1&","&Data!AL1&","&Data!AM1&","&Data!AN1&","&Data!AO1&","&Data!AP1&","&Data!AQ1&","&Data!AR1&","&Data!AS1&","&Data!AT1&","&Data!AU1&","&Data!AV1&","&Data!AW1&","&Data!AX1&","&Data!AY1&","&Data!AZ1&","&Data!BA1&","&Data!BB1&","&Data!BC1&","&Data!BD1&","&Data!BE1&","&Data!BF1&","&Data!BG1&","&Data!BH1&","&Data!BI1&","&Data!BJ1&","&Data!BK1&","&Data!BL1&","&Data!BM1&","&Data!BN1&","&Data!BO1&","&Data!BP1&","&Data!BQ1&","&Data!BR1&","&Data!BS1&","&Data!BT1&","&Data!BU1&","&Data!BV1&","&Data!BW1&","&Data!BX1&","&Data!BY1&","&Data!BZ1&","&Data!CA1&","&Data!CB1&","&Data!CC1&","&Data!CD1&","&Data!CE1&","&Data!CF1&","&Data!CG1&","&Data!CH1&","&Data!CI1&","&Data!CJ1&","&Data!CK1&","&Data!CL1&","&Data!CM1&","&Data!CN1&","&Data!CO1&","&Data!CP1&","&Data!CQ1&","&Data!CR1&","&Data!CS1&","&Data!CT1&","&Data!CU1&","&Data!CV1&","&Data!CW1&","&Data!CX1&","&Data!CY1&","&Data!CZ1&","&Data!DA1&","&Data!DB1&","&Data!DC1&","&Data!DD1&","&Data!DE1&","&Data!DF1&","&Data!DG1&","&Data!DH1&","&Data!DI1&","&Data!DJ1&","&Data!DK1&","&Data!DL1&","&Data!DM1&","&Data!DN1&","&Data!DO1&","&Data!DP1&","&Data!DQ1&","&Data!DR1&","&Data!DS1&","&Data!DT1&","&Data!DU1&","&Data!DV1&","&Data!DW1&","&Data!DX1&","," ","~"),","," "))," ",",")
I copied this all the way down to A3000. This gave me a set of values on each line which were separated by a "|". Obviously, you would need to adapt this to the actual range you are processing. By reducing the size to a single line, I did not run into the 32,767 text limit. Hopefully, you won't either.
I saved this as an MS-DOS text file.
I opened it in MS Word and used its Find/Replace command to replace the paragraph break character (^p) with a "|" and re-saved this as a text file. The resulting file differed from what I wanted to create only by having an extra "|" at the end.
Hopefully, this will work for you or perhaps you need to save it as a Macintosh text file for the Mac version of MS Word to be able to replace the characters at the end of each line.
Not sure if this helps you achieve what you need. It certainly could work if you only need to do this once or occasionally, but it may be a bit of a pain if this is a frequent task.

VBA - Sum Cells with the 'Number Stored as Text' error

In Excel 2010, I am writing VBA to take the SUM of a range of filtered values, and store that result into a variable. The code looks like this:
With Sheets("Output")
.Range("$A:$ZZ").AutoFilter field:=ColIndex(AB), Criteria1:="x"
y = Application.WorksheetFunction.Sum( _
Range(Cells(2, "AC"), Cells(10, "AC")).SpecialCells(xlCellTypeVisible) _
)
This does work, but only when I have manually toyed with the data. When I try to use this formula on my data set unedited, I get a blank result. The problem seems to lie with the data when unedited.
Each number gets the Number Stored as Text (NSaT) error. Changing the type from Text to General causes nothing to happen. I have to open the cell for editing, and then remove focus from the cell for the type to kick in. After that, I can change it back and forth from General to Text, and Excel immediately recognizes this and updates the cell. The Sum function will, at this point, recognize both General and Text field types as a number.
Is there a VBA solution for dealing with these NSaT errors? I have attempted to use 'NumberFormat' on the column, but it does not help. I have also tried manually copying and pasting the data again, even using the special As Value option, but it still has the NSaT error until manually toyed with.

Excel seems to change format of only some columns

Using VBA, I import a csv file and put a bunch of data into several columns.
One of these columns has a date and time. As I need to be able to use just the 'time' part of these cells, I try to convert the entire column to Time by using (and just about every other variation)
Cells(x.y).EntireColumn.NumberFormat = "hh:mm:ss"
or
Range("C1").NumberFormat = "hh:mm:ss"
Range("C1").EntireColumn.NumberFormat = "hh:mm:ss"
However, this does not convert the entire column. I've tried every possible other way of selecting the entire column and changing it (through VB) however still only a portion remains converted.
If I doubleclick on these unconverted cells and press enter they change to the correct format. I realise this is a common problem relating to Calculations but my workbook is set to Automatic Calculations and I've tried setting this in VB too. This doesn't change anything.
The only pattern I can find is that the cells stop being converted when the Day reaches double digits. For example:
Column C
01/05/2013 7:28:56
03/05/2013 13:24:53
07/05/2013 20:13:24
09/05/2013 8:29:22
12/05/2013 9:28:56
15/05/2013 21:14:25
17/05/2013 7:28:56
Becomes:
Column C
7:28:56
13:24:53
20:13:24
8:29:22
12/05/2013 9:28:56
15/05/2013 21:14:25
17/05/2013 7:28:56
In the formula bar up the top for each cell it still shows the whole Date and Time for all cells, not sure if this is related, but doesn't seem to matter in terms of the calculations i have to perform using the Time.
Essentially I have to take the time for a cell in column C and the time from another Cell (also in Date/Time format) and check the difference. After some research I decided the best way was to convert all the cells to a time format and then do my calculations.
Alternatively I could try converting the column to text and using a Split function (using space as a delimiter) and pulling the time out, but I'm having trouble doing this too, as once again trying to convert the entire column to text stops at the double digits for date.
Thanks for reading through all that, any thoughts and help would be appreciated.
Edit: Realised some of my syntax was incorrect in my post, this was however correct inside my macro
another edit: I think this definitely has something to do with the date format... I just realised that before i format them, the dates are m/dd/yyyy and then when it gets to actual double digit days it changes to dd/mm/yyyy, and thats when the problem occurs...
In order to avoid confusion, and as the date always seems to occupy the same width, I recommend to
1) import this column as a text
2) then go over the whole column
For Each C In Range("A:A").Cells
If C <> "" Then
' ....
End If
Next C
3) cut away the leading 11 positions, e.g. C = Mid(C, 11, 99)
4) convert the remaining string to a time, e.g. C = CDate(C) (... yes it works with a time as well, because a time is a fractional part of a date)
Alternatively you may want to capture the date part and bring it into shape, too. See here for some ideas using worksheet formulas.

Resources