sth like string — Common string operations — Python 3.10.4 documentation?
I really fear erlang’s ~F.P.PadModC
(Erlang -- io)
sth like string — Common string operations — Python 3.10.4 documentation?
I really fear erlang’s ~F.P.PadModC
(Erlang -- io)
What is there to fear? It is almost the same as Python instead of %
you use ~
. If anything we will get wrapper over io_lib:format/2
as it is handy for report_cb
in logger handlers.
For example I just had to format a CSS compatible hex color. (#RRGGBB
, eg (0,0,255) -> #0000FF
)
Could not figure that out from the documentation.
Also it is actually two things.
io_lib:format
which I do not like (maybe I’m just too stupid, but not all coders geniuses, and Elixir is mostly a very easy language, so I might be spoiled also)I actually agree with you @Sebb.
I generally like the Erlang documentation and I no problems in translating that into Elixir, but I had a really hard time with the documentation for io_lib:format
and the understanding of this. I believe it’s because I’ve got so used to everything else in Elixir is so intuitive and understandable that most times I just need to skim through the documentation to get back into the groove of things. Which I think is super important in a dynamic language where the language server isn’t always there to help you with introspection.
For future readers, here’s the format needed:
:io.fwrite("#~2.16.0B~2.16.0B~2.16.0B", [r, g, b])
# prints the string "#F27B04"
Values smaller than zero or larger than 255 will be replaced with **
:
:io.fwrite("#~2.16.0B~2.16.0B~2.16.0B", [-r, g, b])
# prints "#**7B04"
:io.fwrite("#~2.16.0B~2.16.0B~2.16.0B", [10*r, g, b])
# prints "#**7B04"
Breakdown in detail:
~2.16.0B
2
is the field width. Without it, values less than 16 will only output a single character16
is called “precision” in the API, but for the B
control sequence it’s the base to use0
is the padding character, because we want 4
to print as 04
not <space>4
I admit, with some patience the docs are understandable.
One thing that confused me are the .
, but I now understand, that they are only needed when one of P, Pad,or Mod right to it is used, here the dot right to 16
is wrong, only needed when Pad
is used.
iex(23)> :io.fwrite("~.16.B", [15])
** (ArgumentError) errors were found at the given arguments:
* 1st argument: format string invalid (truncated)
So what about
iex> "##{r:2.16.0B}{g:2.16.0B}{b:2.16.0B}"
I think that would be useful.
IMO that’s too big of a change - one of the nice things about Elixir is the regularity of the syntax, and that would make #{}
magical in a way that’s not available elsewhere. A more “Elixir-y” solution would be to make the conversion explicit:
"##{to_hex(r)}#{to_hex(g)}#{to_hex(b)}"
...
defp to_hex(v), do: :io_lib.format("~2.16.0B", [v])
Some other gotchas that come to mind:
*
in the various positions) means more tricky syntax"#{some_calculation():i}"
do? “Ignore one thing from the input” makes a lot more sense when the format and the data are fully separated (as in :io
):io.fwrite("~w", [DateTime.utc_now()])
prints
#{'__struct__' => 'Elixir.DateTime',calendar => 'Elixir.Calendar.ISO',day => 1,hour => 22,microsecond => {937508,6},minute => 47,month => 5,second => 18,std_offset => 0,time_zone => <<69,116,99,47,85,84,67>>,utc_offset => 0,year => 2022,zone_abbr => <<85,84,67>>}
That topic gave me an idea for a library. I will try to draft something this weekend.
That’s true. But maybe inside a sigil?
Really? Does not seem too hard, but I dont know too much about parsers.
Just take the output and pass it to the formatter?
# python 3.6
>>> def foo(): return 255
...
>>> f"#{foo():0{2}x}"
'#ff'
may raise
# python 3.6
>>> def foo(): return None
...
>>> f"#{foo():0{2}x}"
TypeError: unsupported format string passed to NoneType.__format__
I do not understand what you mean.
Yes, that’s not nice in this case. So we would be responsible to call sth like to_string()
.