;+
; NAME:
; FLORMAT
;
; AUTHOR:
; Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
; Craig.Markwardt@nasa.gov
;
; PURPOSE:
; Format a string with named format variables
;
; CALLING SEQUENCE:
; RESULT = FLORMAT(FORMAT, [ struct ], [x=x, y=y, ...], [_EXTRA=struct])
;
; DESCRIPTION:
;
; The function FLORMAT is used to easily insert a set of named
; parameters into a string using simple format codes. The key point
; is that format strings use *named* parameters instead of the
; position in the string.
;
; FLORMAT makes it easy to make maintainable and understandable
; format codes. FLORMAT is a convenience routine, which will be most
; suitable for formatting tabular output, but can be used for any
; complicated string formatting job where the positional parameters
; of STRING() become hard to manage. Users of Python will recognize
; FLORMAT as implementing "string interpolation."
;
; The user passes a format string similar to the IDL printf-style
; format string (i.e. using modified "%" notation), and a set of
; named fields either by passing a structure, keywords, or both. The
; output strings are composed by inserting the named fields into the
; format string with any requested formatting.
;
; The function FLORMAT is equivalent to the STRING(...,FORMAT=fmt)
; method of formatting a string, where the format string is allowed
; to have the name of the variable.
;
; Let us consider an example of formatting a time with hours, minutes
; and seconds into a string as HH:MM:SS. One could use FLORMAT()
; like this,
;
; result = flormat('%(hour)02d:%(min)02d:%(sec)02d', $
; hour=hour, min=min, sec=sec)
;
; The variables HOUR, MIN and SEC are allowed to be scalars or
; vectors. The key point here is that the format string contains the
; *named* keyword variables (or structure entries). Unlike STRING(),
; the actual variables can be passed in any order, since the format
; string itself describes in what order the values will be assembled.
; This is similar to string interpolation in Python.
;
; The same variable can appear multiple times in the format string,
; but the user only need to specify that variable once. For example,
;
; result = flormat('Download %(href)s', $
; href='filename.txt')
;
; Note that HREF appears twice in the format string.
;
; INPUT VARIABLES:
;
; FLORMAT() allows you to pass in the values as named keywords as
; shown above, where the keyword values are arrays, or by passing in
; an array of structures. A similar example to the one above is,
;
; S = replicate({hour: 0, min: 0, sec: 0}, 100)
; ; ... fill the structure S with 100 time values ...
; result = flormat('%(hour)02d:%(min)02d:%(sec)02d', s)
;
; In this case S is an array of structures, and the result will be an
; array of strings with the same number of elements as S.
;
; Compare this with standard IDL where a FOR-loop is required, no
; repetition is permitted, and it is difficult to see which format
; code corresponds to which variable. For example,
;
; for i = 0, n_elements(hour)-1 do begin
; result(i) = string(hour(i), min(i), sec(i), $
; format='(%"%02d:%02d:%02d")')
;
; The input structure STRUCT may be an array of structures or a
; structure of arrays. It is also possible pass *both* a structure
; STRUCT and keywords. The important thing is that the each keyword
; and each STRUCT.FIELD must evaluate to the same number of
; elements. If they don't, then the smallest number of elements is
; used.
;
; PRINTF-STYLE FORMAT CODES
;
; FLORMAT() uses format codes in either C printf-style format codes
; (the default), or a new "$" shell-style syntax if /SHELL_STYLE$ is
; set.
;
; FLORMAT() assumes that by default the C printf-style format codes
; are passed. FLORMAT() uses a slightly short-hand notation for
; print-style format codes which saves some space and is more
; flexible.
;
; Standard printf-style format codes are of the form,
; FORMAT='(%"...format here...")' ;; Standard IDL
; The FLORMAT printf-style format codes simply dispense with the
; redundant parentheses and percent symbol,
; FORMAT='...format here...' ;; FLORMAT notation
; This notation improves the readability of the format string, since
; only the actual format string needs to be present. Also, this
; notation does not embed one set of quotation marks within another,
; as the standard IDL notation does, so format strings with quotation
; marks will be easier to compose.
;
; Standard IDL format codes look like this,
; %s - string
; %d - integer
; %04d - integer zero-padded to 4 spaces, etc
;
; The new FLORMAT format strings look like this,
;
; %(name)s - string based on variable named NAME
; %(value)d - integer based on variable named VALUE
; %(index)04d - integer based on variable named INDEX,
; zero-padded to 4 spaces
;
; As you can see, the only difference is the addition of the variable
; name in parenthesis. These names are looked up in the input
; keywords and/or structure passed to FLORMAT().
;
; SHELL-STYLE FORMAT CODES
;
; Shell style "$" is a convenience notation when strict formatting is
; less important. Shell-style "$" format strings will be signaled by
; setting the SHELL_STYLE$ keyword. Note the trailing dollar-sign
; '$'. The format coes will look like this,
;
; $name - variable named NAME will be placed here
; $value - variable named VALUE will be placed here, etc.
;
; This is exactly how Unix shell string interpolation works.
; Variables are substituted into place using their "natural" format
; code, based on the variable type.
;
; result = flormat('Download $href', /shell_style$, $
; href='filename.txt')
;
; Note that quotation marks still need to be escaped as \", just the
; same as calling STRING() or PRINT with a %-style format string.
;
; CAVEATS:
;
; FLORMAT() is a convenience routine meant mostly to improve the
; readability and maintainability of format codes. FLORMAT() is not
; meant for high performance applications. It spends time parsing
; the input format string. It also spends memory building up a
; temporary output structure. However, for most applications such as
; constructing tables of up to thousands of entries, FLORMAT() should
; be perfectly adequate.
;
; The name "FLORMAT" is a play on the words "floor-mat" and "format."
; The "L" in FLORMAT can be thought of standing for "long-form" IDL
; format codes.
;
; PARAMETERS:
;
; FORMAT - format string used to
;
; STRUCT - input structure containing named entries. This should
; either be an array of structures, with each field
; containing a scalar; or, a structure where each field
; contains an array with the same number of elements.
;
; RETURNS:
;
; The resulting formatted strings. The return value will be an
; array of strings containing the same number of elements as passed
; as input.
;
; KEYWORD PARAMETERS:
;
; SHELL_STYLE$ - if set, then the format string is a shell-style
; string.
;
; All named keywords are available to be used as named formats in
; your format code. Values may be either scalar, or vector.
; Vectors dimensions must match the dimensions of STRUCT (if
; STRUCT is passed).
;
; EXAMPLE:
;
;
; ; Additional examples appear above.
;
; SEE ALSO:
;
; STRING, Format codes, C print-style format codes
;
; MODIFICATION HISTORY:
; Written, CM, 14 Sep 2009
; Finalized and documented, CM, 08 Dec 2011
;
; $Id: flormat.pro,v 1.9 2013/03/16 23:29:40 cmarkwar Exp $
;
;-
; Copyright (C) 2011, Craig Markwardt
; This software is provided as is without any warranty whatsoever.
; Permission to use, copy, modify, and distribute modified or
; unmodified copies is granted, provided this copyright and disclaimer
; are included unchanged.
;-
;; ;; Replace '"' by '\"' (poor man's REPSTR)
;; ofmts = strsplit(ofmt, '"', /preserve_null, /extract)
;; nquote = n_elements(ofmts)-1
;; if nquote GT 0 then begin
;; ofmts[0:nquote-1] = ofmts[0:nquote-1] + '\"'
;; ofmt = strjoin(ofmts)
;; endif
ofmt1 = '(%"'+ofmt+'")'
return, string(outs, format=ofmt1, $
am_pm=am_pm, days_of_week=days_of_week, months=months)
end