feat(fstring): implement scientific and percentage formatting
This commit is contained in:
@@ -1,33 +1,48 @@
|
||||
// Basic type
|
||||
print("Basic type")
|
||||
let a = 42
|
||||
print(f"int: {a:d}; hex: {a:x}; HEX: {a:X}; oct: {a:o}; bin: {a:b}")
|
||||
print()
|
||||
|
||||
// Grouping
|
||||
print("Grouping")
|
||||
let b = 1234567890
|
||||
print(f"{b:,}")
|
||||
print(f"{b:_}")
|
||||
print()
|
||||
|
||||
let c = 1234.5678
|
||||
print(f"{c:,._}")
|
||||
print(f"{c:_.,}")
|
||||
print()
|
||||
|
||||
// Sign
|
||||
print("Sign")
|
||||
let d1 = 14
|
||||
let d2 = -26
|
||||
print(f"{d1} {d2}")
|
||||
print(f"{d1:+} {d2:+}")
|
||||
print(f"{d1:-} {d2:-}")
|
||||
print(f"{d1: } {d2: }")
|
||||
print()
|
||||
|
||||
// Percentage
|
||||
print("Percentage")
|
||||
let pts = 19
|
||||
let total = 22
|
||||
print(f"Correct answers: {pts/total:.2%}")
|
||||
print()
|
||||
|
||||
// Precision
|
||||
print("Precision")
|
||||
print(f"{c:8}")
|
||||
print(f"{c:8.2}")
|
||||
print(f"{c:.2}")
|
||||
print(f"{c:.8}")
|
||||
print()
|
||||
|
||||
// Complex
|
||||
print("Scientific")
|
||||
print(f"{a:e}")
|
||||
print(f"{b:e}")
|
||||
print(f"{c:e}")
|
||||
print(f"{d1:e}")
|
||||
print(f"{d2:e}")
|
||||
print(f"{0:e}")
|
||||
print()
|
||||
|
||||
print("Complex")
|
||||
@@ -1,3 +1,4 @@
|
||||
from math import log10, floor
|
||||
from typing import Any, Optional
|
||||
|
||||
from src.core.format_spec.spec import FormatSpec
|
||||
@@ -75,8 +76,12 @@ class StringFormatter:
|
||||
res = obj
|
||||
case TokenType.T_BIN | TokenType.T_DEC | TokenType.T_HEX | TokenType.T_HEX_CAPS | TokenType.T_OCT:
|
||||
res = self.format_int(obj, spec, fmt_type)
|
||||
case TokenType.T_SCI | TokenType.T_FIX | TokenType.T_PCT:
|
||||
res = self.format_float(obj, spec, fmt_type)
|
||||
case TokenType.T_FIX:
|
||||
res = self.format_float_fix(obj, spec, fmt_type)
|
||||
case TokenType.T_PCT:
|
||||
res = self.format_float_fix(obj * 100, spec, TokenType.T_FIX) + "%"
|
||||
case TokenType.T_SCI:
|
||||
res = self.format_float_sci(obj, spec, fmt_type)
|
||||
|
||||
if spec.number.integral.width is not None:
|
||||
res = self.pad(res, spec.number.integral.width)
|
||||
@@ -92,7 +97,7 @@ class StringFormatter:
|
||||
|
||||
return sign + string
|
||||
|
||||
def format_float(self, value: float, spec: FormatSpec, fmt_type: TokenType) -> str:
|
||||
def format_float_fix(self, value: float, spec: FormatSpec, fmt_type: TokenType) -> str:
|
||||
sign: str = self.make_sign(value, spec)
|
||||
value = abs(value)
|
||||
integer: int = int(value)
|
||||
@@ -100,9 +105,16 @@ class StringFormatter:
|
||||
integer_spec = spec.number.integral
|
||||
decimal_spec = spec.number.decimal
|
||||
|
||||
precision: Optional[int] = None
|
||||
if fmt_type == TokenType.T_SCI:
|
||||
precision = 6
|
||||
|
||||
if decimal_spec is not None:
|
||||
if decimal_spec.precision is not None:
|
||||
decimal = round(decimal, decimal_spec.precision)
|
||||
precision = decimal_spec.precision
|
||||
|
||||
if precision is not None:
|
||||
decimal = round(decimal, precision)
|
||||
|
||||
integer_str: str = self.format_int_part(integer, fmt_type, integer_spec.grouping)
|
||||
decimal_str: str = self.format_int_part(int(str(decimal)[2:]), fmt_type, None if decimal_spec is None else decimal_spec.grouping)
|
||||
@@ -111,6 +123,14 @@ class StringFormatter:
|
||||
|
||||
return f"{sign}{integer_str}{decimal_str}"
|
||||
|
||||
def format_float_sci(self, value: float, spec: FormatSpec, fmt_type: TokenType) -> str:
|
||||
sign: str = self.make_sign(value, spec)
|
||||
value = abs(value)
|
||||
mag: int = 0 if value == 0 else floor(log10(value))
|
||||
coef: float = value / (10 ** mag)
|
||||
coef_str: str = self.format_float_fix(coef, spec, fmt_type)
|
||||
return f"{sign}{coef_str}e{mag:+03d}"
|
||||
|
||||
def format_int_part(self, value: int, fmt_type: TokenType, grouping: Optional[Token]):
|
||||
groups: int = 4
|
||||
string: str = str(value)
|
||||
|
||||
Reference in New Issue
Block a user