Click here to Skip to main content
15,881,803 members
Articles / Programming Languages / F#

F#3 : Formatting text

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
21 May 2014CPOL6 min read 22.1K   2   2
One of the things you will most likely need to do when you work with any language is format text, and surprise surprise F# is no different.

One of the things you will most likely need to do when you work with any language is format text, and surprise surprise F# is no different.

Since F# is a .NET language we can always make use of Console.WriteLine(..) and String.Format(..) where we could use any of the regular formatters that you have used in your regular .NET code.

However F# also supports a more C syntax like technique which is available within the Core.Printf module. One function within that can be used instead of the Console.WriteLine(..) .NET class usage.

The F# equivalent function that you would use to write to the standard output is printfn, which is actually the preferred method when dealing with text formatting in F#.

Why is printfn preferred over Console.WriteLine(..) ?

There are several reasons that printfn is preferred, some of the main reasons are shown below:

  • Static type checking. Which means if we pass an int value where a string is expected, we are warned about this
  • As printfn is a native F# function, is acts just like any other F# function. Where you do certain F# things, such as possibly partially applying the function (which is something we will try and cover a bit more in a subsequent post)
  • It will have baked in support for standard F# types

Lets just spend a bit more time on the statically typed point above. Consider the following code snippets

C#
// incorrect type
printfn "should be a decimal value %d" "cat"
//this works
printfn "should be a decimal value %d" 42
// incorrect type but works
Console.WriteLine("should be a decimal value {0}" , "cat")


// wrong number of parameters provided
printfn "this only expected 1 arg of type decimal %d" 42 "dog"
// wrong number of parameters provided but works
Console.WriteLine("this only expected 1 arg of type decimal {0}" , 42, "dog")
// this works as expected
printfn "this only expected 2 args of type decimal %d and string %s" 42 "dog"

If we now look at a screen shot of this code actually in the Visual Studio IDE, we can indeed see that the lines that we expected to fail are clearly shown as being in error:

image

How we use printfn?

So now that we know why we should use printfn, how do we use it?

Well probably the best place to start is by looking at some of the standard formatters available when dealing with values. The following table illustrates the standard operators that are available to you:

I have taken these directly from MSDN : http://msdn.microsoft.com/en-us/library/ee370560.aspx

TypeDescription
%bFormats a bool, formatted as true or false.
%cFormats a character.
%sFormats a string, formatted as its contents, without interpreting any escape characters.
%d, %iFormats any basic integer type formatted as a decimal integer, signed if the basic integer type is signed.
%uFormats any basic integer type formatted as an unsigned decimal integer.
%xFormats any basic integer type formatted as an unsigned hexadecimal integer, using lowercase letters a through f.
%XFormats any basic integer type formatted as an unsigned hexadecimal integer, using uppercase letters A through F.
%oFormats any basic integer type formatted as an unsigned octal integer.
%e, %E, %f, %F, %g, %GFormats any basic floating point type (float, float32) formatted using a C-style floating point format specifications.
%e, %EFormats a signed value having the form [-]d.dddde[sign]ddd where d is a single decimal digit, dddd is one or more decimal digits, ddd is exactly three decimal digits, and sign is + or -.
%fFormats a signed value having the form [-]dddd.dddd, where dddd is one or more decimal digits. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision.
%g, %GFormats a signed value printed in f or e format, whichever is more compact for the given value and precision.
%MFormats a Decimal value.
%OFormats any value, printed by boxing the object and using its ToString method.
%A, %+AFormats any value, printed with the default layout settings. Use %+A to print the structure of discriminated unions with internal and private representations.
%a

A general format specifier, requires two arguments. The first argument is a function which accepts two arguments: first, a context parameter of the appropriate type for the given formatting function (for example, a TextWriter), and second, a value to print and which either outputs or returns appropriate text.

The second argument is the particular value to print.

%tA general format specifier, requires one argument: a function which accepts a context parameter of the appropriate type for the given formatting function (a TextWriter)and which either outputs or returns appropriate text. Basic integer types are byte, sbyte, int16, uint16, int32, uint32, int64, uint64, nativeint, and unativeint. Basic floating point types are float and float32.

I would recommend you have a look at that MSDN link, as it contains additional information that may be useful when you need to do some fine grained formatting.

So what about creating nice formatting other than standard out

So we have now seen how to write nicely formatted output to the standard output (printfn did this), but what about if we wanted to use formatted string in other places? What if we wanted to bind a string value to a nicely formatted string that we constructed using some of the formatters above, or even wanted to write to a StringBuilder or TextWriter, does F# enable us to do that easily?

Well yes actually it does, you will find a great many other useful functions in the Core.Printf module. The full list at time of writing this post was as follows:

ValueDescription
bprintfPrints to a StringBuilder.
eprintfPrints formatted output to stderr.
eprintfnPrints formatted output to stderr, adding a newline.
failwithfPrints to a string buffer and raises an exception with the given result. Helper printers must return strings.
fprintfPrints to a text writer.
fprintfnPrints to a text writer, adding a newline.
kbprintfLike bprintf, but calls the specified function to generate the result. See kprintf.
kfprintfLike fprintf, but calls the specified function to generate the result. See kprintf.
kprintfLike printf, but calls the specified function to generate the result. For example, these let the printing force a flush after all output has been entered onto the channel, but not before.
kspintfLike sprintf, but calls the specified function to generate the result. See kprintf.
printfPrints formatted output to stdout.
printfnPrints formatted output to stdout, adding a newline.
sprintfPrints to a string by using an internal string buffer and returns the result as a string. Helper printers must return strings.

I am not going to through all of these but I will go through the most common ones:

bprintf

Prints to a StringBuilder.

C#
let builder = new StringBuilder(524288)
Printf.bprintf builder "This will be a string line : %s\r\n" "cat" 
Printf.bprintf builder "This will be a bool line : %b\r\n" true
Printf.bprintf builder "This will be a int line : %u\r\n" 42
Printf.bprintf builder "This will be a hex line : %X\r\n" 255

printfn "%s" (builder.ToString())

This will give this output in a F# Console Application

image

fprintf

Prints to a text writer.

C#
use sw = new StreamWriter(@"c:\temp\fprintfFile.txt")

fprintf sw "This is a string line %s\r\n" "cat"
fprintf sw "This is a int line %i" 10

sw.Close()

This will result in a file being created in temp

image

sprintf

Prints to a string by using an internal string buffer and returns the result as a string. Helper printers must return strings.

C#
let result = Printf.sprintf "This will return a formatted string : %s\r\n" "cat" 
printfn "%s" result

This will give this output in a F# Console Application

image

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
QuestionIndexed placeholders for localization Pin
Grant Frisken25-May-14 21:30
Grant Frisken25-May-14 21:30 
AnswerRe: Indexed placeholders for localization Pin
Sacha Barber26-May-14 6:24
Sacha Barber26-May-14 6:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.