#set document(title: "3.2 Formatted strings", author: "OpenStax / XYZ Homework") #set page(width: 8.5in, height: auto, margin: 1in) #import "@preview/cetz:0.5.2" #set text(font: ("STIX Two Text", "Libertinus Serif", "New Computer Modern"), size: 10.5pt, lang: "en") #show math.equation: set text(font: ("STIX Two Math", "New Computer Modern Math")) #set par(justify: true, leading: 0.62em, spacing: 0.9em) #set enum(spacing: 1.1em) // room between list items so tall inline fractions don't collide #set list(spacing: 1.1em) #set table(stroke: 0.5pt + rgb("#c7ccd3")) #let BLUE = rgb("#183B6F") // brand navy — section bars + example/solution labels (white on navy 11.09:1) #let ORANGE = rgb("#A94509") // brand primary-700 — AA-safe deep orange for TEXT (5.93:1 on white; raw brand #F37021 is 2.94:1 and must never carry text) #let RED = rgb("#DC2626") // brand error-600 #let GREEN = rgb("#059669") // brand success-600 (decoration only; small green text uses green-text #007942) #show heading.where(level: 1): it => block(width: 100%, above: 0pt, below: 16pt, fill: gradient.linear(BLUE, rgb("#2C5AA0")), inset: (x: 14pt, y: 12pt), radius: 3pt, text(fill: white, weight: "bold", size: 19pt, it.body)) #show heading.where(level: 2): it => block(width: 100%, above: 18pt, below: 10pt, fill: BLUE, inset: (x: 10pt, y: 6pt), radius: 2pt, text(fill: white, weight: "bold", size: 12pt, it.body)) #show heading.where(level: 3): it => text(fill: ORANGE, weight: "bold", size: 12.5pt, it.body) #show heading.where(level: 4): it => text(fill: BLUE, weight: "bold", size: 10.5pt, it.body) #let examplebox(label, title, body) = block(width: 100%, breakable: true, fill: rgb("#EFF1F5"), stroke: 0.5pt + rgb("#CFDDF0"), radius: 4pt, inset: 10pt, above: 12pt, below: 12pt)[ #block(below: 6pt)[#box(fill: BLUE, inset: (x: 6pt, y: 2pt), radius: 2pt, text(fill: white, weight: "bold", size: 8.5pt, label)) #h(0.4em) #strong[#title]] #body] // rail = decorative left rule (raw brand token); labelcolor = AA-safe label text shade #let notebox(label, rail, labelcolor, tint, body) = block(width: 100%, breakable: true, fill: tint, stroke: (left: 3pt + rail), inset: (left: 10pt, rest: 8pt), radius: (right: 4pt), above: 11pt, below: 11pt)[ #text(fill: labelcolor, weight: "bold", size: 7.5pt, tracking: 0.5pt)[#upper(label)] #linebreak() #body] #let solutionbox(body) = block(above: 4pt, below: 8pt)[ #text(fill: BLUE, weight: "bold", size: 8.5pt)[Solution] #linebreak() #body] #let figph(msg) = block(width: 100%, height: 60pt, fill: rgb("#f6f7f9"), stroke: (paint: rgb("#c7ccd3"), dash: "dashed"), radius: 4pt, inset: 10pt)[ #align(center + horizon, text(fill: rgb("#889"), style: "italic", size: 9pt, msg))] // Standardize inlined figure sizes: measure the natural CeTZ canvas, then scale to a // consistent envelope (aspect-aware; see build_typst.py FIG_* constants). Unlike the // print preamble, dimensions are FLOORED: in an editor a user can trim a figure to a // degenerate 1-D shape (a bare line), and w/h or tw/w would then divide by zero. #let _STD_W = 3.5 #let _WIDE_W = 5.6 #let _MAX_H = 3.4 #let _ASPECT_WIDE = 2.2 #let _UPSCALE_MAX = 1.15 #let stdfig(body) = context { let m = measure(body) let w = calc.max(m.width / 1in, 0.01) let h = calc.max(m.height / 1in, 0.01) let tw = if w / h > _ASPECT_WIDE { _WIDE_W } else { _STD_W } let s = calc.min(tw / w, _MAX_H / h, _UPSCALE_MAX) align(center, box(scale(x: s * 100%, y: s * 100%, reflow: true, body))) } #show figure: set block(breakable: false) #set figure(gap: 8pt) #show figure.caption: set text(size: 8.5pt, fill: rgb("#555")) == 3.2#h(0.6em)Formatted strings === Learning objectives By the end of this section you should be able to - Use f-strings to simplify output with multiple values. - Format numbers with leading zeros and fixed precision. === F-strings A #strong[formatted string literal] (or #strong[f-string]) is a string literal that is prefixed with "f" or "F". A #strong[replacement field] is an expression in curly braces ({}) inside an f-string. Ex: The string f"Good morning, {first} {last}!" has two replacement fields: one for a first name, and one for a last name. F-strings provide a convenient way to combine multiple values into one string. #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Printing an f-string] #link("https://www.openstax.org/r/printing-f-string")[Printing an f-string; ch 3, video 2] ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Basic f-strings] ] === Formatting numbers Programs often need to display numbers in a specific format. Ex: When displaying the time, minutes are formatted as two-digit integers. If the hour is 9 and the minute is 5, then the time is "9:05" (not "9:5"). In an f-string, a replacement field may include a format specifier introduced by a colon. A #strong[format specifier] defines how a value should be formatted for display. Ex: In the string f"{hour}:{minute:02d}", the format specifier for minute is 02d. #figure(table( columns: 4, align: left, inset: 6pt, table.header([Format], [Description], [Example], [Result]), [d], [Decimal integer (default integer format).], [f"{12345678:d}"], ['12345678'], [,d], [Decimal integer, with comma separators.], [f"{12345678:,d}"], ['12,345,678'], [10d], [Decimal integer, at least 10 characters wide.], [f"{12345678:10d}"], ['  12345678'], [010d], [Decimal integer, at least 10 characters wide, with leading zeros.], [f"{12345678:010d}"], ['0012345678'], [f], [Fixed-point (default is 6 decimal places).], [f"{math.pi:f}"], ['3.141593'], [.4f], [Fixed-point, rounded to 4 decimal places.], [f"{math.pi:.4f}"], ['3.1416'], [8.4f], [Fixed-point, rounded to 4 decimal places, at least 8 characters wide.], [f"{math.pi:8.4f}"], ['  3.1416'], [08.4f], [Fixed-point, rounded to 4 decimal places, at least 8 characters wide, with leading zeros.], [f"{math.pi:08.4f}"], ['003.1416'], )) #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Formatting numbers] ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Mad lib (f-string)] A #link("https://openstax.org/r/100fstring")[mad lib] is a funny story that uses words provided by a user. The following mad lib is based on four words (user input in bold): Enter a name: #strong[Buster] Enter a noun: #strong[dog] Enter an adjective: #strong[super] Verb ending in -ing: #strong[swimming] Buster, the super dog, likes to go swimming. Most of the code for this mad lib is already written. Complete the code below by writing the f-string. name = input("Enter a name: ") noun = input("Enter a noun: ") adjective = input("Enter an adjective: ") verb\_ing = input("Verb ending in -ing: ") print() print(f"") \# TODO: edit this line only ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Wage calculator] You just landed a part-time job and would like to calculate how much money you will earn. Write a program that inputs the time you start working, the time you stop working, and your hourly pay rate (example input in bold): Starting hour: #strong[9] Starting minute: #strong[30] Stopping hour: #strong[11] Stopping minute: #strong[0] Hourly rate: #strong[15] Based on the user input, your program should calculate and display the following results: Worked 9:30 to 11:00 Total hours: 1.5 Payment: \$22.50 For this exercise, you need to write code that (1) calculates the total payment and (2) formats the three output lines. Use f-strings and format specifiers to display two-digit minutes, one decimal place for hours, and two decimal places for payment. The input code has been provided as a starting point. Assume the use of a 24-hour clock. Ex: 16:15 is used instead of 4:15pm. start\_hour = int(input("Starting hour: ")) start\_min = int(input("Starting minute: ")) stop\_hour = int(input("Stopping hour: ")) stop\_min = int(input("Stopping minute: ")) rate = float(input("Hourly rate: ")) print() ]