Skip to content

Formatted string literals#

Code Example

Runnable Example in Jac and JacLib

with entry {
    # Basic f-string examples
    name = "John";
    print(f"Hello {name}");
    print(F'Hello {name}');
    print(f"{{It is myname}}, name is: {name}");

    # Numeric operations and formatting
    x = 10;
    y = 20;
    z = 65;
    pi = 3.14159;

    print(f"Sum of {x} and {y} is {x + y}");
    print(f"Hex: {y:x}");
    print(f"Binary: {x:b}");
    print(f"Value: {z:.2f}");
    print(f"Hex: {z:10}");
    print(f"Pi: {pi:.2f}");

    # String formatting and conversions
    b = "b";
    name = "José";
    value = "Hello\nWorld";

    print(f"Debug: {b!a}");
    print(f"Default: {name}");
    print(f"ASCII: {name!a}");
    print(f"repr: {value!r}");
    print(f"str: {value!s}");
    print(f"ascii: {value!a}");

    # Nested f-strings
    name = "John";
    print(f"name is {name} {f'inner: {name}'}");

    # Multiline f-strings with triple quotes
    multiline_msg = f"""Hello {name},
    This is a multiline f-string.
    Your value is: {value}
    Sum of {x} + {y} = {x + y}""";
    print(multiline_msg);

    another_multiline = f'''Welcome {name}!
    Here's your data:
    - X: {x}
    - Y: {y}
    - Z: {z}
    Binary of {x}: {x:b}''';
    print(another_multiline);

    # Nested triple quote f-strings
    nested_triple = f"""Outer: {name} {f'''Inner triple: {value}'''}""";
    print(nested_triple);

    # Complex JSON-like formatting
    complex_format = f"""
    Debug Report for {name}:
    {{
        "x": {x},
        "y": {y},
        "hex_y": "{y:x}",
        "repr_value": {value!r}
    }}
    """;
    print(complex_format);

    # Raw f-strings for paths and patterns
    path = "home";
    file = "test.txt";

    # Basic raw f-strings
    raw_path = rf"C:\Users\{name}\{path}\{file}";
    raw_path2 = fr'D:\Projects\{name}\{file}';
    print(raw_path);
    print(raw_path2);

    # Multiline raw f-strings
    raw_multiline = rf"""Path: C:\Users\{name}\Documents\
    File: {file}
    Full: C:\Users\{name}\Documents\{file}""";
    print(raw_multiline);

    raw_multiline2 = fr'''Regex pattern: \d+\.\d+
    Name: {name}
    Pattern for {name}: \b{name}\b''';
    print(raw_multiline2);

    # Raw f-strings with special patterns
    regex_pattern = rf"\b{name}\w*\b";
    raw_with_newline = rf"Line 1\nLine 2 with {name}\tTabbed";
    windows_path = rf"\\server\share\{name}\documents\{file}";

    print(regex_pattern);
    print(raw_with_newline);
    print(windows_path);
}
with entry {
    # Basic f-string examples
    name = "John";
    print(f"Hello {name}");
    print(F'Hello {name}');
    print(f"{{It is myname}}, name is: {name}");

    # Numeric operations and formatting
    x = 10;
    y = 20;
    z = 65;
    pi = 3.14159;

    print(f"Sum of {x} and {y} is {x + y}");
    print(f"Hex: {y:x}");
    print(f"Binary: {x:b}");
    print(f"Value: {z:.2f}");
    print(f"Hex: {z:10}");
    print(f"Pi: {pi:.2f}");

    # String formatting and conversions
    b = "b";
    name = "José";
    value = "Hello\nWorld";

    print(f"Debug: {b!a}");
    print(f"Default: {name}");
    print(f"ASCII: {name!a}");
    print(f"repr: {value!r}");
    print(f"str: {value!s}");
    print(f"ascii: {value!a}");

    # Nested f-strings
    name = "John";
    print(f"name is {name} {f'inner: {name}'}");

    # Multiline f-strings with triple quotes
    multiline_msg = f"""Hello {name},
    This is a multiline f-string.
    Your value is: {value}
    Sum of {x} + {y} = {x + y}""";
    print(multiline_msg);

    another_multiline = f'''Welcome {name}!
    Here's your data:
    - X: {x}
    - Y: {y}
    - Z: {z}
    Binary of {x}: {x:b}''';
    print(another_multiline);

    # Nested triple quote f-strings
    nested_triple = f"""Outer: {name} {f'''Inner triple: {value}'''}""";
    print(nested_triple);

    # Complex JSON-like formatting
    complex_format = f"""
    Debug Report for {name}:
    {{
        "x": {x},
        "y": {y},
        "hex_y": "{y:x}",
        "repr_value": {value!r}
    }}
    """;
    print(complex_format);

    # Raw f-strings for paths and patterns
    path = "home";
    file = "test.txt";

    # Basic raw f-strings
    raw_path = rf"C:\Users\{name}\{path}\{file}";
    raw_path2 = fr'D:\Projects\{name}\{file}';
    print(raw_path);
    print(raw_path2);

    # Multiline raw f-strings
    raw_multiline = rf"""Path: C:\Users\{name}\Documents\
    File: {file}
    Full: C:\Users\{name}\Documents\{file}""";
    print(raw_multiline);

    raw_multiline2 = fr'''Regex pattern: \d+\.\d+
    Name: {name}
    Pattern for {name}: \b{name}\b''';
    print(raw_multiline2);

    # Raw f-strings with special patterns
    regex_pattern = rf"\b{name}\w*\b";
    raw_with_newline = rf"Line 1\nLine 2 with {name}\tTabbed";
    windows_path = rf"\\server\share\{name}\documents\{file}";

    print(regex_pattern);
    print(raw_with_newline);
    print(windows_path);
}
# Basic f-string examples
name = "John"
print(f"Hello {name}")
print(F'Hello {name}')
print(f"{{It is myname}}, name is: {name}")

# Numeric operations and formatting
x = 10
y = 20
z = 65
pi = 3.14159

print(f"Sum of {x} and {y} is {x + y}")
print(f"Hex: {y:x}")
print(f"Binary: {x:b}")
print(f"Value: {z:.2f}")
print(f"Hex: {z:10}")
print(f"Pi: {pi:.2f}")

# String formatting and conversions
b = "b"
name = "José"
value = "Hello\nWorld"

print(f"Debug: {b!a}")
print(f"Default: {name}")
print(f"ASCII: {name!a}")
print(f"repr: {value!r}")
print(f"str: {value!s}")
print(f"ascii: {value!a}")

# Nested f-strings
name = "John"
print(f"name is {name} {f'inner: {name}'}")

# Multiline f-strings with triple quotes
multiline_msg = f"""Hello {name},
    This is a multiline f-string.
    Your value is: {value}
    Sum of {x} + {y} = {x + y}"""
print(multiline_msg)

another_multiline = f'''Welcome {name}!
    Here's your data:
    - X: {x}
    - Y: {y}
    - Z: {z}
    Binary of {x}: {x:b}'''
print(another_multiline)

# Nested triple quote f-strings
nested_triple = f"""Outer: {name} {f'''Inner triple: {value}'''}"""
print(nested_triple)

# Complex JSON-like formatting
complex_format = f"""
    Debug Report for {name}:
    {{
        "x": {x},
        "y": {y},
        "hex_y": "{y:x}",
        "repr_value": {value!r}
    }}
"""
print(complex_format)

# Raw f-strings for paths and patterns
path = "home"
file = "test.txt"

# Basic raw f-strings
raw_path = rf"C:\Users\{name}\{path}\{file}"
raw_path2 = fr'D:\Projects\{name}\{file}'
print(raw_path)
print(raw_path2)

# Multiline raw f-strings
raw_multiline = rf"""Path: C:\Users\{name}\Documents\
    File: {file}
    Full: C:\Users\{name}\Documents\{file}"""
print(raw_multiline)

raw_multiline2 = fr'''Regex pattern: \d+\.\d+
    Name: {name}
    Pattern for {name}: \b{name}\b'''
print(raw_multiline2)

# Raw f-strings with special patterns
regex_pattern = rf"\b{name}\w*\b"
raw_with_newline = rf"Line 1\nLine 2 with {name}\tTabbed"
windows_path = rf"\\server\share\{name}\documents\{file}"

print(regex_pattern)
print(raw_with_newline)
print(windows_path)
Jac Grammar Snippet
fstring: F_DQ_START fstr_dq_part* F_DQ_END
       | F_SQ_START fstr_sq_part* F_SQ_END
       | F_TDQ_START fstr_tdq_part* F_TDQ_END
       | F_TSQ_START fstr_tsq_part* F_TSQ_END
       | RF_DQ_START rfstr_dq_part* F_DQ_END
       | RF_SQ_START rfstr_sq_part* F_SQ_END
       | RF_TDQ_START rfstr_tdq_part* F_TDQ_END
       | RF_TSQ_START rfstr_tsq_part* F_TSQ_END

fstr_dq_part: F_TEXT_DQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

fstr_sq_part: F_TEXT_SQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

fstr_tdq_part: F_TEXT_TDQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

fstr_tsq_part: F_TEXT_TSQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

// Add separate rules for raw f-strings
rfstr_dq_part: RF_TEXT_DQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

rfstr_sq_part: RF_TEXT_SQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

rfstr_tdq_part: RF_TEXT_TDQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

rfstr_tsq_part: RF_TEXT_TSQ | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

fformat: F_FORMAT_TEXT | D_LBRACE | D_RBRACE | LBRACE expression CONV? (COLON fformat*)? RBRACE

Description

Formatted String Literals (f-strings)#

This document demonstrates the usage of formatted string literals (f-strings) in both Python and Jac languages. F-strings provide a concise and readable way to include expressions inside string literals.

Basic F-string Syntax#

F-strings are prefixed with f or F and use curly braces {} to embed expressions.

Python:

name = "John"
print(f"Hello {name}")
print(F'Hello {name}')

Jac:

name = "John";
print(f"Hello {name}");
print(F'Hello {name}');

Escaping Curly Braces#

To include literal curly braces in f-strings, double them:

print(f"{{It is myname}}, name is: {name}")

Numeric Operations and Formatting#

F-strings support expressions and format specifiers for numbers:

Basic Operations#

x = 10
y = 20
print(f"Sum of {x} and {y} is {x + y}")

Number Base Conversions#

  • Hexadecimal: {value:x} - converts to lowercase hex
  • Binary: {value:b} - converts to binary
  • Decimal formatting: {value:.2f} - formats to 2 decimal places
y = 20
x = 10
z = 65
pi = 3.14159

print(f"Hex: {y:x}")        # Output: 14
print(f"Binary: {x:b}")     # Output: 1010
print(f"Value: {z:.2f}")    # Output: 65.00
print(f"Pi: {pi:.2f}")      # Output: 3.14

Field Width#

print(f"Hex: {z:10}")       # Right-aligned in 10 character field

String Formatting and Conversions#

F-strings support conversion flags to change how values are represented:

  • !r - calls repr() on the value
  • !s - calls str() on the value
  • !a - calls ascii() on the value
b = "b"
name = "José"
value = "Hello\nWorld"

print(f"Debug: {b!a}")      # ASCII representation
print(f"Default: {name}")   # Default string representation
print(f"ASCII: {name!a}")   # ASCII-safe representation
print(f"repr: {value!r}")   # repr() representation with quotes
print(f"str: {value!s}")    # str() representation
print(f"ascii: {value!a}")  # ASCII representation with escapes

Nested F-strings#

F-strings can be nested inside other f-strings:

name = "John"
print(f"name is {name} {f'inner: {name}'}")

Multiline F-strings#

F-strings work with triple quotes for multiline strings:

Triple Double Quotes#

multiline_msg = f"""Hello {name},
This is a multiline f-string.
Your value is: {value}
Sum of {x} + {y} = {x + y}"""

Triple Single Quotes#

another_multiline = f'''Welcome {name}!
Here's your data:
- X: {x}
- Y: {y}
- Z: {z}
Binary of {x}: {x:b}'''

Nested Triple Quote F-strings#

nested_triple = f"""Outer: {name} {f'''Inner triple: {value}'''}"""

Complex Formatting Examples#

F-strings are useful for generating structured output like JSON:

complex_format = f"""
Debug Report for {name}:
{{
    "x": {x},
    "y": {y},
    "hex_y": "{y:x}",
    "repr_value": {value!r}
}}
"""

Raw F-strings#

Raw f-strings combine the benefits of raw strings (no escape sequence processing) with f-string interpolation. They are prefixed with rf or fr.

Basic Raw F-strings#

path = "home"
file = "test.txt"
name = "John"

raw_path = rf"C:\Users\{name}\{path}\{file}"
raw_path2 = fr'D:\Projects\{name}\{file}'

Multiline Raw F-strings#

raw_multiline = rf"""Path: C:\Users\{name}\Documents\
File: {file}
Full: C:\Users\{name}\Documents\{file}"""

raw_multiline2 = fr'''Regex pattern: \d+\.\d+
Name: {name}
Pattern for {name}: \b{name}\b'''

Common Use Cases for Raw F-strings#

File Paths (Windows):

windows_path = rf"\\server\share\{name}\documents\{file}"

Regular Expressions:

regex_pattern = rf"\b{name}\w*\b"

Literal Backslashes:

raw_with_newline = rf"Line 1\nLine 2 with {name}\tTabbed"

Language Differences#

Both Python and Jac support the same f-string syntax with minor differences:

Feature Python Jac
Statement termination Optional Required ;
Syntax f"text {expr}" f"text {expr}";
All formatting features
Raw f-strings
Nested f-strings

Best Practices#

  1. Use f-strings for readability - They are more readable than .format() or % formatting
  2. Combine with format specifiers - Use : notation for number formatting
  3. Use raw f-strings for paths - Especially useful for Windows file paths and regex patterns
  4. Leverage conversion flags - Use !r, !s, !a for debugging and special representations
  5. Escape braces when needed - Double curly braces {{ }} for literal braces

Summary#

F-strings provide a powerful and intuitive way to format strings in both Python and Jac. They support: - Variable interpolation - Expression evaluation - Number formatting and base conversion - String conversion flags - Multiline strings - Raw string processing - Nested f-strings

This makes them the preferred choice for most string formatting tasks due to their readability and performance.