Frugghi /
SwiftLCS
Swift implementation of the longest common subsequence (LCS) algorithm.
Loading repository data…
objecthub / repository
Implementation of Common Lisp's `format` procedure from scratch in Swift 5 as a more powerful and complete replacement of `printf`.
This framework implements
Common Lisp's format procedure
from scratch in Swift. format is a procedure that produces formatted text using a
format string similar to printf. The formatting formalism is significantly more expressive
compared to printf. It allows users to display numbers in various formats (e.g. hex, binary,
octal, roman numerals, natural language), apply conditional formatting, output text in a
tabular format, iterate over data structures, and even apply format recursively to handle
data that includes their own preferred formatting strings.
The documentation of this framework includes:
Here are a few examples to get a quick impression of the usage of clformat:
clformat("~D message~:P received. Average latency: ~,2Fms.", args: 17, 4.2567)
⇒ "17 messages received. Average latency: 4.26ms."
clformat("~D file~:P ~A. Average latency: ~,2Fms.", args: 1, "stored", 68.1)
⇒ "1 file stored. Average latency: 68.10ms."
The primary formatting procedure provided by framework CLFormat is clformat. It has
the following signature:
func clformat(_ control: String,
config: CLControlParserConfig? = CLControlParserConfig.default,
locale: Locale? = nil,
tabsize: Int = 4,
linewidth: Int = 80,
displayWidth: Bool = false,
args: Any?...) throws -> String
control is the formatting string. It is using the formatting language described in the
next section to define how the output will be formatted. config refers to the
format configuration
which determines how the control string and the arguments get parsed and interpreted. This
parameter gets usually omitted, unless a user wants to define their own control formatting
language. locale refers to a Locale object which is used for executing
locale-specific directives. tabsize defines the maximum number of space characters that
correspond to a single tab character. linewidth specifies the number of characters per
line (this is used by the justification directive only). If displayWidth is set to true,
then the justification, write, and ascii directives will use the terminal display width of
a string provided as an argument to clformat to pad and justify this argument. This makes
it possible to include characters such as emojies where one character often occupies multiple
characters when output. Characters provided in directives need to always be of width 1,
otherwise the output is undefined.
Finally, args refers to the
sequence of arguments provided for inclusion in the formatting procedure. The control
string determines how these arguments will be injected into the final output that
function clformat returns. Here is an example:
try clformat("~A is ~D year~:P old.", args: "John", 32)
⇒ "John is 32 years old."
try clformat("~A is ~D year~:P old.", args: "Vicky", 1)
⇒ "Vicky is 1 year old."
There is also an overloaded variant
of clformat which supports arguments provided as
an array. It is otherwise equivalent to the first variant.
func clformat(_ control: String,
config: CLControlParserConfig? = CLControlParserConfig.default,
locale: Locale? = nil,
tabsize: Int = 4,
linewidth: Int = 80,
displayWidth: Bool = false,
arguments: [Any?]) throws -> String
Finally, there are is an overloaded function
clprintf which prints out the formatted
string directly to the standard output port. Via the terminator argument it is possible
to control whether a newline character is added automatically.
func clprintf(_ control: String,
config: CLControlParserConfig? = CLControlParserConfig.default,
locale: Locale? = nil,
tabsize: Int = 4,
linewidth: Int = 80,
displayWidth: Bool = false,
args: Any?...,
terminator: String = "\n") throws
func clprintf(_ control: String,
config: CLControlParserConfig? = CLControlParserConfig.default,
locale: Locale? = nil,
tabsize: Int = 4,
linewidth: Int = 80,
displayWidth: Bool = false,
arguments: [Any?],
terminator: String = "\n") throws
Note that, by default, both clformat and clprintf use the formatting directives as
specified by CLControlParserConfig.default.
This is a mutable parser configuration that
can be used to influence all invocations of clformat and clprintf which don't provide
their own parser configuration.
Similar to how printf is integrated into Swift's String API, framework CLFormat
provides two new String initializers
which make use of the CLFormat formatting mechanism.
They can be used interchangably with clformat to allow for a more object-oriented style as
opposed to the procedural nature of clformat.
extension String {
init(control: String,
config: CLControlParserConfig? = nil,
locale: Locale? = nil,
tabsize: Int = 4,
linewidth: Int = 80,
displayWidth: Bool = false,
args: Any?...) throws
init(control: String,
config: CLControlParserConfig? = nil,
locale: Locale? = nil,
tabsize: Int = 4,
linewidth: Int = 80,
displayWidth: Bool = false,
arguments: [Any?]) throws
}
Every single time clformat is being invoked, a control language parser is converting
the control string into an easier to process intermediate format. If a control string is
being used over and over again by a program, it makes sense to convert the control string
only once into its intermediate format and reuse it whenever a new list of arguments is
applied. The following code shows how to do that. Values of struct CLControl represent
the intermediate format of a given control string.
let control = try CLControl(string: "~A = ~,2F (time: ~4,1,,,'0Fms)")
let values: [[Any?]] = [["Stage 1", 317.452, 12.7],
["Stage 2", 570.159, 41.2],
["Stage 3", 123.745, 9.4]]
for args in values {
print(try control.format(arguments: args))
}
This is the generated output:
Stage 1 = 317.45 (time: 12.7ms)
Stage 2 = 570.16 (time: 41.2ms)
Stage 3 = 123.74 (time: 09.4ms)
The control string used by clformat and related functions and constructors consists of
characters that are copied verbatim into the output as well as
formatting directives. All formatting directives start with a
tilde (~) and end with a single character identifying the type of the directive.
Directives may take prefix parameters written immediately after the tilde
character, separated by comma. Both integers and characters are allowed as parameters.
They may be followed by formatting modifiers :, @, and +. This is the general
format of a formatting directive:
~param1,param2,...mX
where m = (potentially empty) sequence of modifier characters ":", "@", and "+"
X = character identifying the directive type
This grammar describes the syntax of directives formally in BNF:
<directive> ::= "~" <modifiers> <char>
| "~" <parameters> <modifiers> <char>
<modifiers> ::= <empty>
| ":" <modifiers>
| "@" <modifiers>
| "+" <modifiers>
<parameters> ::= <parameter>
| <parameter> "," <parameters>
<parameter> ::= <empty>
| "#"
| "v"
| <number>
| "-" <number>
| <character>
<number> ::= <digit>
| <digit> <number>
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<character> ::= "'" <char>
The following sections introduce a few directives and explain how directives are combined to build control strings that define expressive formatting instructions.
Here is a simple control string which injects a readable description of an argument via
the directive ~A:
"I received ~A as a response"
Directive ~A refers to a the next argument provided to clformat when compiling the
formatted output:
clformat("I received ~A as a response", args: "nothing")
⇒ "I received nothing as a response"
clformat("I received ~A as a response", args: "a long email")
⇒ "I received a long email as a response"
Directive ~A may be given parameters to influence the formatted output. The first
parameter of ~A-directives defines the minimal length. If the length of the textual
representation of the next argument is smaller than the minimal length, padding characters
are inserted:
clformat("|Name: ~10A|Location: ~13A|", args: "Smith", "New York")
⇒ "|Name: Smith |Location: New York |"
clformat("|Name: ~10A|Location: ~13A|", args: "Williams", "San Francisco")
⇒ "|Name: Williams |Location: San Francisco|"
clformat("|Name: ~10,,,'_@A|Location: ~13,,,'-A|", args: "Garcia", "Los Angeles")
⇒ "|Name: ____Garcia|Location: Los Angeles--|"
The third example above utilizes more than one parameter and, in one case, includes a
@ modifier. The directive ~13,,,'-A defines the first and the fourth parameter. The
second and third parameter are omitted and thus defaults are used. The fourth parameter
defines the padding character. If character literals are used in the parameter list,
they are prefixed with a quote '. The directive ~10,,,'_@A includes an @ modifier
which will result in padding of the output on the left.
It is possible to inject a parameter from the list of arguments. The following examples
show how parameter v is used to do this for formatting a floating-point number with
a configurable number of fractional digits.
clformat("length = ~,vF", args: 2, Double.pi)
⇒ "length = 3.14"
clformat("leng
Selected from shared topics, language and repository description—not editorial ratings.
Frugghi /
Swift implementation of the longest common subsequence (LCS) algorithm.
faif /
Implementation of common algorithms
SwiftOnSails /
Swift implementations of common fuzzy string matching algorithms.
kumarnagender09 /
A TreeView is a hierarchical representation of data that allows users to expand and collapse nodes to navigate through the hierarchy. In Swift for iOS, a common approach to implementing a TreeView is by using a UITableView with custom cells.
simonnickel /
A collection of useful helper implementations, common extensions, convenience definitions and workarounds.
weihotline /
A list of common data structures implemented in Swift.