I'm having some issues finding out how to cast a string array to a specific type.
Here is my code
type plItem = {
sku: string
name: string
size: string
buy: decimal
sell: decimal
barcode: string
}
// .... ( get values from google sheets )
let values:IList<IList<Object>> = response.Values
let pl = values |> Seq.map ( fun item -> Seq.toArray )
At the end of the code - pl is now an array of strings. I want to make it an aray of the type ( above ) plItem I'm not sure of the easiest way to to this.
If I understand the question correctly, you have a list of list where the outer list represents rows and the nested list represents columns. You want to turn the rows into records and the columns correspond to individual record fields.
There is no automatic way of doing that. You'll just have to extract individual columns and convert them to an appropriate type (either by unboxing the type into a string or by getting the string value and then parsing it). Something like this:
open System
open System.Collections.Generic
type plItem = {
sku: string
name: string
size: string
buy: decimal
sell: decimal
barcode: string
}
let values:IList<IList<Object>> =
[| [| box "12660"; box "Probiotics 14 Strains"; box "60 VCaps";
box "31.46"; box "50.35"; box "9403067126606"; |] :> IList<_>
|] :> IList<_>
let pl = values |> Seq.map (fun row ->
{ sku = unbox row.[0]
name = unbox row.[1]
size = unbox row.[2]
buy = decimal (unbox<string> row.[3])
sell = decimal (unbox<string> row.[4])
barcode = unbox row.[5] })
I want to write an extended version of F# printfn function that prints current time in addition to text. Something like this:
let printimefn fmt =
let time = DateTime.Now
let strtime = sprintf "%02d:%02d:%02d" time.Hour time.Minute time.Second
printfn "%s %A" strtime fmt
Unfortunately this doesn't work as expected. The "fmt" argument loses its type Printf.TextWriterFormat<'T>.
I can force its type by using type annotation:
let printimefn (fmt : Printf.TextWriterFormat<'T>) =
let time = DateTime.Now
let strtime = sprintf "%02d:%02d:%02d" time.Hour time.Minute time.Second
printfn "%s %A" strtime fmt
But then the result of printimefn becomes unit, and not 'T. So it still doesn't work. I wonder what is the right way of to write a custom printfn function.
This can be done with Printf.ksprintf
let printimefn fmt =
let time = DateTime.Now
Printf.ksprintf (
fun s ->
printfn "%02d:%02d:%02d %s" time.Hour time.Minute time.Second s)
fmt
I want to demonstrate this by moving the reading of the time out of the function, for two reasons. Primarily to demonstrate how to add one or more arguments that are not consumed by ksprintf, but also because we should have a function that does not have side effects. If you want the time to be read inside the function, then instead create a wrapper function that reads the time, then calls the following function.
First there are two explicit arguments not passed on to ksprintf. Then follows implicitly the format string and any implicit arguments the format string requires.
let tsprintf (dateTime: DateTime) (tag: string) =
let dateTimeString =
dateTime.ToString (#"yyyy/MM/dd HH:mm:ss",
System.Globalization.CultureInfo.InvariantCulture)
Printf.ksprintf (fun formatString ->
"[" + dateTimeString + " <" + tag + ">] " + formatString)
let testTime = DateTime(1987, 12, 31, 11, 59, 58)
let message = tsprintf testTime "007" "Hello %s!" "James Bond"
message.Dump() // LINQPad output : [1987/12/31 11:59:58 <007>] Hello James Bond!
The InvariantCulture in combination with the chosen time format string makes sure the result you see is exactly what's in the comment at the end, no matter where or what.
The reason I use DateTime.ToString, is that this formats DateTime whichever way you want. Formatting it in ksprintf doesn't seem like a good idea.
The arguments not consumed by ksprintf are explicitly declared in tsprintf. The format string and the following arguments for ksprintf are not declared explicitly, but they follow all explicitly declared arguments.
I have an integer which I want to convert to a string with leading zeros.
So I have 1 and want to turn it into 01. 14 should turn into 14 not 014.
I tried:
let str = (string 1).PadLeft(2, '0') // visual studio suggested this one
let str = (string 1).PadLeft 2 '0'
let str = String.PadLeft 2 '0' (string 1)
But neither work :(
When I search for something like this with F# I get stuff with printfn but I don't want to print to stdout :/
Disclaimer: This is my first F#
You can use sprintf which returns a string rather than printing to stdout. Any of the print functions that start with an s return a string.
Use %0i to pad with zeroes. Add the length of the intended string between 0 and i. For example, to pad to four zeroes, you can use:
sprintf "%04i" 42
// returns "0042"
I am new to F# and would like to have an advice.
I would like to use the GetDigitValue function.
open System
open System.Drawing
open System.Globalization
let getSubscript ichar =
match ichar with
|1 -> GetDigitValue(843)
| _ -> GetDigitVale(852)
I have the following error: The value or constructor 'getDigitValue" is not defined.
Without further information I can't really tell what you are trying to do.
GetDigitValue is a static method of the CharUnicodeInfo class.
It is used like this:
let testString = "1234567890"
let digitValue = CharUnicodeInfo.GetDigitValue(testString, 3)
This returns the digit value for the 3rd character in the string. It also works with a single character too.
let test = '5'
let digitvalue = CharUnicodeInfo.GetDigitValue(test)
Update:
To get the superscript of a string I think the Numeric value will return this:
let superscriptTwo ="U+00B2"
let numericvalue = CharUnicodeInfo.GetNumericValue(superscriptTwo)
I would like to get the superscript of numbers.
Then I think you want this function that gives a unicode character that is the superscript of the given digit:
let superscriptOf n =
if 0<=n && n<10 then "⁰¹²³⁴⁵⁶⁷⁸⁹".[n] else
invalidArg "n" "Not a single digit number"
Note that F# supports unicode in F# code. You can even use unicode variable names like λ in F# code!
I'm getting a Finnish date string that looks like:
29.7.2011 9:27
I'm trying to cast this string to a Date object in VB6. I've tried using the Format function but it doesn't seem to swallow the date string or I'm doing something wrong. These are some approaches I've tried:
theDate = Format(dateString, "General Date")
theDate = Format(dateString, "DD.MM.YYYY MM:HH")
Any ideas? Thanks.
Rather than manually parsing the string yourself, which is prone to errors, and which gets messy if you have to deal with multiple date formats, you can call out to the OLE Automation library (which VB6 uses internally for many things, including type conversions) to do the conversion for you. It can convert strings in any date/time format supported by Windows back into a raw Date.
Full disclosure: I agree with the sentiment in Deanna's
answer: in general, you should try to use an unambiguous date/time
format when converting dates to and from strings, but if you cannot do
this for some reason, the solution outlined here should be fairly robust, as long as you know ahead of time what specific format the incoming date string will be in.
Below is an example of a DateFromString function that uses the VarDateFromStr function internally to convert a formatted date/time String into a Date.
Example Usage
Convert a Finnish date string to a Date and display it:
MsgBox DateFromString("29.7.2011 9:27", fl_FI)
On my machine (US English settings), this displays "7/29/2011 9:27 AM", which is the correct date and time (July 29).
Code
Place the code below into a new module (.bas file) in your project to use it. The code currently supports parsing US English (en_US) and Finnish (fl_FI) date strings, but you can add support for more locales if needed. See Locale IDs assigned by Microsoft for a complete list of locale ID's.
Option Explicit
Public Enum LocaleIDs
en_US = &H409 ' English (United States)
fl_FI = &H40B ' Finnish
' [[ Add other Locale ID's here as needed ]] '
End Enum
Private Declare Function VarDateFromStr Lib "oleaut32.dll" ( _
ByVal psDateIn As Long, _
ByVal lcid As Long, _
ByVal uwFlags As Long, _
ByRef dtOut As Date) As Long
Private Const S_OK = 0
Private Const DISP_E_BADVARTYPE = &H80020008
Private Const DISP_E_OVERFLOW = &H8002000A
Private Const DISP_E_TYPEMISMATCH = &H80020005
Private Const E_INVALIDARG = &H80070057
Private Const E_OUTOFMEMORY = &H8007000E
'
' Converts a date string in the specified locale to a VB6 Date.
'
' Example:
'
' Convert a Finnish date string as follows:
'
' DateFromString("29.7.2011 9:27", fl_FI)
'
Public Function DateFromString(ByVal sDateIn As String, ByVal lcid As LocaleIDs) As Date
Dim hResult As Long
Dim dtOut As Date
' Do not want user's own settings to override the standard formatting settings
' if they are using the same locale that we are converting from.
'
Const LOCALE_NOUSEROVERRIDE = &H80000000
' Do the conversion
hResult = VarDateFromStr(StrPtr(sDateIn), lcid, LOCALE_NOUSEROVERRIDE, dtOut)
' Check return value to catch any errors.
'
' Can change the code below to return standard VB6 error codes instead
' (i.e. DISP_E_TYPEMISMATCH = "Type Mismatch" = error code 13)
'
Select Case hResult
Case S_OK:
DateFromString = dtOut
Case DISP_E_BADVARTYPE:
Err.Raise 5, , "DateFromString: DISP_E_BADVARTYPE"
Case DISP_E_OVERFLOW:
Err.Raise 5, , "DateFromString: DISP_E_OVERFLOW"
Case DISP_E_TYPEMISMATCH:
Err.Raise 5, , "DateFromString: DISP_E_TYPEMISMATCH"
Case E_INVALIDARG:
Err.Raise 5, , "DateFromString: E_INVALIDARG"
Case E_OUTOFMEMORY:
Err.Raise 5, , "DateFromString: E_OUTOFMEMORY"
Case Else
Err.Raise 5, , "DateFromString: Unknown error code returned from VarDateFromStr (0x" & Hex(hResult) & ")"
End Select
End Function
You can use DateSerial and 'TimeSerial' in the following way
dateString = "29.7.2011 9:27"
Dim theDate as Date
dim yyyy as Integer
dim mm as Integer
dim dd as Integer
dim hh as integer
dim mm as integer
yyyy = mid(dateString,6,4)
mm = mid(dateString,4,1)
dd = mid(dateString,1,2)
hh = mid(dateString,11,1)
mm = mid(dateString,13,2)
theDate = DateSerial(yyyy,mm,dd) + TimeSerial(hh,mm,0)
now you theDate is a Date object and can be formatted the way you want
MsgBox Format(theDate,"yyyy-MMM-dd") 'This will display the a message with 2011-Jul-29
If your date string is not padded with zeros (for example: 2.4.2011 instead of 02.04.2011) then you will need to loop through the string to find the bits and parts of the date that you will be needing.
Finnish systems should be able to parse these correctly using CDate(). If you're parsing it on a non finnish system and the format is fixed, then you will need to split it up in code:
Dim Parts() as string, dateParts() As String, timeParts() as string
parts = Split(dateString, " ")
dateParts = Split(parts(0), ".")
timeParts = Split(parts(1), ":")
theDate = DateSerial(dateParts(2), dateParts(1), dateParts(0)) + TimeSerial(timeParts(0), timeParts(1), 0)
You will probbaly want to add error handling and sanity checking to that but that is the basic idea.
Note that converting dates to and from string values will be error prone unless using very explicit unambigious agreed formats like ISO 8601, RFC 822 dates, and the iCal RFC 2445 standard.
Parsing is messy at best but here is a shorter sample how to do it
Private Sub Command1_Click()
MsgBox Format$(TryParse("29.7.2011 9:27"), "yyyymmdd hh:mm:ss")
End Sub
Private Function TryParse(sFinnishDate As String) As Date
Dim vSplit As Variant
vSplit = Split(Replace(Replace(sFinnishDate, ".", " "), ":", " "))
On Error Resume Next
TryParse = DateSerial(vSplit(2), vSplit(1), vSplit(0)) + TimeSerial(vSplit(3), vSplit(4), 0)
On Error GoTo 0
End Function