Convert number in sci format to string in excel - excel

I need to convert a column of alpha-numeric values to strings in an Excel function. CStr(value) works fine, UNLESS the value is something like 123E4. In that case, Excel treats the value as 1230000 and returns the string "1230000". Using Format(value,"#") yields the same result. The result I want is the string "123E4".
How can I get this?
The input cells are downloaded from a web site. They use the "General" format. I pass the value in a cell to the following function.
Function Var2Str(varA1 As Variant, Optional strFmt As String = "#") As String
Dim strTry As String
Dim strMsg As String
Debug.Print varA1, VarType(varA1), TypeName(varA1)
strTry = CStr(varA1)
Select Case VarType(varA1)
Case vbDouble
strTry = Format(varA1, strFmt)
Case vbString
'no further action
Case Else
strMsg = "Unhandled VarType in Var2Str" _
& vbCrLf & vbTab & "vara1 = " & varA1 _
& vbCrLf & vbTab & "varType = " _
& VarType(varA1) & vbCrLf & vbTab _
& "TypeName = " & TypeName(varA1)
MsgBox strMsg, vbOKOnly, "Information"
End Select
Var2Str = strTry
Debug.Print Var2Str
End Function

You could try (1) getting what you see in a string, and (2) using that to set the value of the target cell.
Sub test_format2()
Dim r As Range, r1 As Range
Set r = Selection
For Each r1 In r
Dim n1 As String
n1 = r1.Text ' (1)
r1.Offset(0, 1).Formula = "'" & n1 ' (2)
Next r1
End Sub
This seems to be the only bullet proof option.
For instance, 1.2e8 seems to be a challenging case when varying column width.

Variations on this question are common here. An oz of prevention is worth a pound of cure. So best to prevent the problem instead of trying to cure it after the fact:
In order to prevent Excel from converting certain alpha-numeric data that look like numbers or dates, into numbers or dates, you must IMPORT rather than OPEN the file. When you do that, the Text-import-wizard will open and you can designate the column as text before excel does the conversion.
Exactly how to do this depends on your version of Excel. In more recent versions, it will be on the Get & Transform tab on the Data Ribbon and may say something like From Text/CSV.
If you need to automate this, you can record a VBA macro while doing it.
I entered the values you listed above in a document using Notepad, and saved it as a csv file.
I then used the above method and got this result:

For me, the best solution was to use Workbook.OpenText to open the downloaded files and use the fieldinfo parameter to force the relevant columns to be formatted as text. The only trick is to make sure the downloaded file name has extension .txt, not.csv. For unknown reasons, VBA will not respect the fieldinfo parameter to open files with the .csv extension, regardless of the file content.

Related

Replace customer ID with VBA variable in FindById() function?

I am trying to automate some of my SAP work with VBA. I am stuck in the sign in as the script to customer price file is
session.FindById("wnd[1]/usr/cntlPRM_CC3000_1/shellcont/shell").SapEvent "Frame0", "sapbu_cl= &sapse_cl= &sapin_cl=S1F1E6~L&evtcode=ENTR&scroll_pos=0&S1F1E1L=2000&S1F1E2L=10&S1F1E3L=**98701**&S1F1E4L=&S1F1E4H=&S1F1E5L=&S1F1E5H=&S1F1E6L=12.10.2022", "sapevent:S1F1"
This is working well for the individual customer ID but I would like to loop through all the customers with different ID's specified in (Sheet 1, starting from A2). Therefore in this script I would need to use variable to replace the customer ID 98701. I found an instruction of using Cvar(Customer). However it leaves the Customer cell empty.
The code is below:
Dim i As Integer
Dim Customer As String
i = 2
Do Until IsEmpty(Cells(i, 1))
Customer = Range("A" & i)
On Error Resume Next
...
session.FindById("wnd[1]/usr/cntlPRM_CC3000_1/shellcont/shell").SapEvent "Frame0", _
"sapbu_cl= &sapse_cl= &sapin_cl=S1F1E6~L&evtcode=ENTR&scroll_pos=0&S1F1E1L=2000" _
& "&S1F1E2L=10&S1F1E3L=Cvar(Customer)&S1F1E4L=&S1F1E4H=" _
& "&S1F1E5L=&S1F1E5H=&S1F1E6L=12.10.2022", _
"sapevent:S1F1"
...
i = i + 1
Loop
Session.FindById(...) seems to be string and I cannot include variant as a value to it.
The cell has a field name as well to write or point out directly.
However I cannot find instructions on how to point to the certain field name directly in this case or include the variant to the Session.FindById string. Other solutions are welcome also!
You should use CStr instead and concatenate the strings correctly
session.FindById("wnd[1]/usr/cntlPRM_CC3000_1/shellcont/shell").SapEvent "Frame0", _
"sapbu_cl= &sapse_cl= &sapin_cl=S1F1E6~L&evtcode=ENTR&scroll_pos=0&S1F1E1L=2000" _
& "&S1F1E2L=10&S1F1E3L=" & CStr(Customer) & " S1F1E4L=&S1F1E4H=" _
& "&S1F1E5L=&S1F1E5H=&S1F1E6L=12.10.2022", _
"sapevent:S1F1"
Maybe the following links shed light on the topic string concatenation
How can I concatenate strings in VBA?
Concatenating strings containing " and & characters

date subtraction doesn't appear correctly vhen generating .log file

I currently have a log file that get generated when you click on a button.
At the beginning of the .log you have a preview with different information such as the login, url of a server etc... But you also have the date of the beginning of the process and the date for the end. Both are in the long date format and are displayed correctly in the log file.
That log file takes the information from a sheet the preview part is static and is a range ("A1:C13") and the rest of the log is beneath but still in the columns ("A:C").
The cells in excel :
I want to add a line that shows the difference between the two date, to quickly see the time the process took.
However when I'm creating the log file, I get the time difference in number.
eg : in excel the cell with the format shows 00:01:55 but in the log file I get 0,001331
The output in the .log :
So far I tried :
To force the format in vba when the export in processing
To copy/paste in value with the hour format to not show the subtraction in the cell
different kind of format but it wasn't conclusive
You'll find the code that create the log file here :
Private Sub iExportLog(Optional LogPath As String, Optional bouton As String)
Dim NF As Integer, C As Range, posi As Integer
Dim date_nom As String
Dim drct As String
NF = FreeFile
drct = ThisWorkbook.path & "\_LogELB"
Set C = iFLog.Range("A1")
' iFLog = the sheet
' Things I tried :
'iFLog.Range("C12") = Format(iFLog.Range("C11").Value - iFLog.Range("C2").Value, "hh:mm:ss")
'iFLog.Range("C12").NumberFormat = "hh:mm:ss"
'
posi = InStrRev(ThisWorkbook.Name, ".")
If Dir(drct, vbDirectory) = "" Then MkDir (ThisWorkbook.path & "\" & "_LogElb")
date_nom = Format(CStr(Now), "yyyy_mm_dd_hh_mm_ss_")
If LogPath = "" Then LogPath = drct & "\" & bouton & "_" & date_nom & ".log"
Open LogPath For Append As #NF
Do While C.Value <> ""
Print #NF, C.Value & vbTab & vbTab & vbTab & C.Offset(0, 1).Value & vbTab & C.Offset(0, 2).Value
Set C = C.Offset(1, 0)
Loop
Close #NF
End Sub
I don't have a lot of practice with manipulating dates but I know that it can be painful.
Is there a way to display a date subtraction correctly when generating a .log/.txt file ?
If you write a formatted time string to a cell then Excel will interpret that as a time value and "undo" your formatting, converting the value back to a numeric value (though the display format may hide that).
If you want to keep the "hh:mm:ss" format then first set the cell format to "Text", or prepend the string with ' before placing it in the cell. Or read the cell's Text property instead of Value

Concatenate values of more cells in a single variable in vba

I have an excel file with four columns: name, surname, address, area.
There are a lot of rows.
Is there a way to concatenate all the values of every single row in a variable, using vba?
I need a variable that should contain something like this:
(name1, surname1, address1, area1); (name2, surname2, address2, area2); (name3, surname3, address3, area3)...
If you have the following data in your worksheet
Then the following code will read the data into an array …
Option Explicit
Public Sub Example()
Dim RangeData() As Variant ' declare an array
RangeData = Range("A1:D5").Value2 ' read data into array
End Sub
… with the following structure:
Alternatively you can do something like
Public Sub Example()
Dim DataRange As Range
Set DataRange = Range("A2:D5")
Dim RetVal As String
Dim Row As Range
For Each Row In DataRange.Rows
RetVal = RetVal & "(" & Join(Application.Transpose(Application.Transpose(Row.Value2)), ",") & "); "
Next Row
Debug.Print RetVal
End Sub
To get this output:
(name1, surname1, address1, area1); (name2, surname2, address2, area2); (name3, surname3, address3, area3); (name4, surname4, address4, area4);
.. is there a way to write the result like a sort of list that shows all the values of the cells of the range?
Yes, there is. In addition to PEH's valid answers and disposing of Excel version MS365 you might also use
Dim s as String
s = Evaluate("ArrayToText(A2:D5, 1)") ' arg. value 1 representing strict format
resulting in the following output string:
{"name1","surname1","address1","area1";"name2","surname2","address2","area2";"name3","surname3","address3","area3";"name4","surname4","address4","area4"}
Syntax
ARRAYTOTEXT(array, [format])
The ARRAYTOTEXT function returns an array of text values from any specified range. It passes text values unchanged, and converts non-text values to text.
The format argument has two values, 0 (concise default format) and 1 (strict format to be used here to distinguish different rows, too):
Strict format, i.e. value 1 includes escape characters and row delimiters. Generates a string that can be parsed when entered into the formula bar. Encapsulates returned strings in quotes except for Booleans, Numbers and Errors.
Thank you for your answers, suggestions, ideas and hints. I am sorry if my question was not so clear, all the solutions you added were perfect and extremely elegant.
In the end I found a way - a dumber way in comparison to all the things you wrote - and I solved with a for statement.
I did like this:
totRow = ActiveSheet.UsedRange.Rows.Count
For i = 1 To totRow
name = Cells(i, 1)
surname = Cells(i, 2)
address = Cells(i, 3)
area = Cells(i, 4)
Example = Example & "(" & name & ", " & surname & ", " & address & ", " & area & "); "
Next i
Range("E1").Value = Example
It works (it does what I wanted to do), but I noticed a little limit: if the rows are a lot I can't keep the whole text in the variable.

Writing Ranges into formulas with VBA

I am using variable ranges, and want to insert those ranges into a formula that can be saved in a document that does not use VBA.
Do I have to use a with statement?
My If Statement works until I try and insert a relative range. I searched and didn't see much on this, so this issue is probably so simply I am an idiot.
The program will be doing things all over the worksheet, so relative coding is needed. The number of items in the range changes with each iteration. I will be using an end range integer [myRange] for the number instead of 10, but I wanted to simplify what I am struggling with into the smallest steps.
Dim Test As String
Test = "=IF(COUNTIF(" & ActiveCell.Offset(1, 0).Address & ":" & ActiveCell.Offset(10, 0).Address & "" _
& ")," & """Not Complete""" & "," & "" & """"")"
ActiveCell.Formula = Test
Desired output in target cell:
"=IF(COUNTIF($J$3:$J$12),"Not Complete","")"
As mentioned in comments, your COUNTIF statement is currently invalid. What are you counting in the range J3:J12? This needs to be added (in place of "CRITERIA" in below solution) before your equation will be valid
Test = "=IF(COUNTIF(" _
& ActiveCell.Offset(1).Resize(10).Address(True, True) _
& ",""CRITERIA""), ""Not Complete"", """")"
If you want your output to actually have the quotes you can output
Chr(34) & Test & Chr(34) which seems cleaner than wrapping the whole string in quotes from a readability point of view IMO

How to write a function that can combine two columns of indefinite length

I have a table in excel that has two columns, call them Tags and Note.
Tags can be empty cell or one tag, or many tags separated by a comma. (each tag is a string)
Note is just an arbitrary sentence (a note).
Note that a tag/tags do NOT reflect a specific note.
I would like to write a function that outputs a string that contains an ID (beginning with 0 for first row), the note and the tag/tags associated with that note.
My function must be able to work if I enter a new row/rows.
So far, I think i've managed to find a function that can read the end of my table. Now I need to be able to process Column A (Tags) to a specific format then concatenate my processed columns to a format similar to this:
{"id":0,"note":"contents of colB","tags":["tag1","tag2", etc]}
This is what I have :(
Sub Parse()
ActiveWorkbook.Sheets.Add.Name = "Result"
idindex = 0
For Each Line In Sheets("Template").Range("B2:B" &
Sheets("Template").Range("B2").End(xlDown).Row)
I'm not familiar with VBA but if I can figure out how to process the columns and append the id, i think I can figure out the formatting.
Might want to see this for good info on how to find the "last" row in a range/column/sheet/etc. Also a good practice to use Option Explicit which forces you to declare all variables (helps prevent typos, and other hard-to-trace errors that arise from implicit typing, etc.).
This is pretty basic string manipulation/string building. You'll need to use some of the built in VBA functions like Join, Split, etc., and you'll need to escape your quotation marks, so something like this:
Sub Parse()
Dim thisCell As Range
Dim id As Long
Dim columnRange As Range
Dim note As String
Dim tags As String
Dim output As String
ActiveWorkbook.Sheets.Add.Name = "Result"
id = 0
With Sheets("Template")
Set columnRange = .Range("B2:B" & .Range("B2").End(xlDown).Row)
For Each thisCell In columnRange
note = thisCell.Value
tags = thisCell.Offset(0, -1).Value
output = FormatOutput(id, note, tags)
' Remove the next line unless you want to print on the same worksheet in column C:
thisCell.Offset(0, 1).Value = output
' This line prints to the Result sheet:
Sheets("Result").Cells(id + 1, 1) = output
id = id + 1
Next
End With
End Sub
I made this fancy function to format the output based on the paramaters: id, thisNote (string) and theseTags (which we expect is the comma-delimited string of tags). I find it easier to build the parts like this when scripting, rather than trying to keep track of all my quotes and whether they're properly escaped/etc.:
Function FormatOutput(id As Long, thisNote As String, theseTags As String) As String
Const OPEN_ITEM As String = "{""id"":"
Const OPEN_NOTE As String = " ""note"":"
Const OPEN_TAGS As String = " ""tags"": ["
Const CLOSE_ITEM As String = "]}"
Const DBLQUOTE As String = """"
Const COMMA As String = ","
FormatOutput = OPEN_ITEM & CStr(id) & _
OPEN_NOTE & DBLQUOTE & thisNote & DBLQUOTE & COMMA & _
OPEN_TAGS & _
IIF(Len(Trim(theseTags)) = 0, "", _
DBLQUOTE & Join(Split(theseTags, COMMA), DBLQUOTE & COMMA & DBLQUOTE) & DBLQUOTE) & _
CLOSE_ITEM
End Function
And that gives me an output like:
{"id":0 "note":"this is a note", "tags": ["tag1","tag3","tag5"]}
It handles notes without tags and vice-versa:
That function (FormatOutput) is the brains behind this operation. It should (hopefully) be pretty straightforward, but this part is a little tricky if you're unfamiliar with the built-ins:
DBLQUOTE & Join(Split(theseTags, COMMA), DBLQUOTE & COMMA & DBLQUOTE) & DBLQUOTE
This ensures that we wrap each of our tag substrings in quotation marks for the output. The DBLQUOTE at the beginning puts a " before the first item, and likewise at the end puts a " after the last item.
Then we (Split(theseTags, COMMA)) split the delimited string on the commas, and Join them back with a new delimiter "," between each.
We need to do all of this tomfoolery because we're building a string that contains quotation marks, which are otherwise treated as either the beginning or end of a string.

Resources