Reputation: 1721
How does one use sprintf to format an integer to display commas as thousands separators?
I know how to do it using String.Format, but I can't find a way to do it using sprintf.
EDIT: Based on Fyodor Soikin's comment below, I tried this code:
printf "%a" (fun writer (value:int) -> writer.Write("{0:#,#}", value)) 10042
let s = sprintf "%a" (fun writer (value:int) -> writer.Write("{0:#,#}", value)) 10042
The printf call works (but writes to standard output, whereas I want to get a string I can assign to the Text or Content property of a WPF control, for instance).
The sprintf call fails with error FS0039: The field, constructor or member 'Write' is not defined.
If I could fix this error, then this might be the most direct solution possible, and when combined with partial application would be as concise as a built-in version.
Upvotes: 11
Views: 9237
Reputation: 4008
Purely on the grounds that my numbers I needed this facility on are ALWAYS integers, and I was doing this in Terraform, my example:
strrev(
join(
",",
[
for chunk in chunklist(
split(
"",
strrev(
var.value
)
)
),
3
) : join("", chunk)
]
)
)
So the following steps are taken (as a way to explain this).
1234567890
)."0987654321"
).["0", "9", "8", "7", "6", "5", "4", "3", "2", "1"]
).[["0", "9", "8"], ["7", "6", "5"], ["4", "3", "2"], ["1"]
).["098", "765", "432", "1"]
).,
("098,765,432,1"
)."1,234,567,890"
).I wonder if this pattern is doable in other languages. 100% admit that it is a bit convoluted, but it achieved my goal, in the language I was using.
Upvotes: 0
Reputation: 401
In pure C...
char* StringFormatIntCommas(char* szDest, int64_t s64Value)
{
char szTemp[32];
uint64_t u64Value = ABS(s64Value); // Drop Signage
if (szDest == NULL) // Validate params
return NULL;
while (u64Value)
{
strcpy(szTemp, szDest); // Preserve Back end
if (u64Value >= 1000)
sprintf(szDest, ",%03d", (int32_t)(u64Value % 1000)); // Next triple ',00n'
else
sprintf(szDest, "%d", (int32_t)(u64Value % 1000)); // Last triple 'n'
u64Value = u64Value / 1000; // Reduce
strcat(szDest, szTemp); // Append Back end
}
if (s64Value < 0) // Pre-Append Negative Sign
{
strcpy(szTemp, szDest); // Preserve Back end
strcpy(szDest, "-"); // Negative sign up front
strcat(szDest, szTemp); // Append back end
}
return szDest;
}
Upvotes: 0
Reputation: 5014
Here is a function:
let thousands n =
let v = (if n < 0 then -n else n).ToString()
let r = v.Length % 3
let s = if r = 0 then 3 else r
[ yield v.[0.. s - 1]
for i in 0..(v.Length - s)/ 3 - 1 do
yield v.[i * 3 + s .. i * 3 + s + 2]
]
|> String.concat ","
|> fun s -> if n < 0 then "-" + s else s
and here is another one with some helper extension members:
type System.String with
member this.Substring2(from, n) =
if n <= 0 then ""
elif from >= this.Length then ""
elif from < 0 then this.Substring2(0, n + from)
else this.Substring(from, min n (this.Length - from))
member this.Left n = if n < 0
then this.Substring2(0, this.Length + n)
else this.Substring2(0, n )
member this.Right n = this.Substring2(max 0 (this.Length - n), this.Length)
let thousands (n:int) =
let rec thousands acc =
function
| "" -> acc
| x -> thousands (x.Right 3 + if acc = "" then "" else "," + acc) (x.Left -3)
if n < 0 then -n else n
|> string
|> thousands ""
|> fun s -> if n < 0 then "-" + s else s
Upvotes: 0
Reputation: 28764
Since you can't do that with the Printf module, I do it like this:
/// Calls ToString on the given object, passing in a format-string value.
let inline stringf format (x : ^a) =
(^a : (member ToString : string -> string) (x, format))
And then call it like this:
someNumber |> stringf "N0"
Upvotes: 6
Reputation: 24996
This works but there should be a simpler way.
let thousands(x:int64) =
System.String.Format("{0:#,0}", x)
let s = sprintf "%s" (thousands(0L))
printfn "%s" s
let s = sprintf "%s" (thousands(1L))
printfn "%s" s
let s = sprintf "%s" (thousands(1000L))
printfn "%s" s
let s = sprintf "%s" (thousands(1000000L))
printfn "%s" s
0
1
1,000
1,000,000
A slightly better version
let printNumber (x : int) : string =
System.String.Format("{0:N0}",x)
Upvotes: 3