Sdk: Add sprintf function for strings

Created on 15 Feb 2012  路  34Comments  路  Source: dart-lang/sdk

_This issue was originally filed by @ltackmann_


A function like Java's String.format (http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html) og C's sprintf would be really usable when formatting complex output.

String s = String.format("Welcome %s at %s", ["Dart", "http://dartlang.org"]);

It might be worthwhile to consider adding i18n when formatting, just like Java's DecimalFormat etc.

area-library core-n type-enhancement

Most helpful comment

Things like localized strings really benefit from string formatting support, too. Sentence structure and word order is completely different in different languages, so being able to put a placeholder in a string for something like a name makes it much easier.

i.e. var finalString = String.format(myLocalizedString, userName);
So, if myLocalizedString is something like "Welcome {0}", then the result of the above might be something like: "Welcome Derek" in English, but something different in another language, but the translator can put the placeholder in the right place according to the relevant sentence structure for that language.

All 34 comments

Have you tried using Dart's String interpolation? Would be curious to learn what aspects of format/sprintf you're missing from Dart's String interpolation.


_Added Area-Language, WontFix labels._

_This comment was originally written by @ltackmann_


Interpolation is nice, but more cumbersome than String.format when you want to control the formatting, consider these examples

Format number with up to 8 leading zeroes

sprintf("%08d", $number);

Round number to 3 digits after decimal point

sprintf("%.3f", $number);

Alternatively one should be able to register a DecimalFormatter and DateFormatter class that can be invoked in toString calles (kinda like they do in Java) this makes i18n easier but is more cumbersome than printf.

_This comment was originally written by andrew.penne...@gmail.com_


Yes, yes, and yes. Interpolation is mere syntactical sugar compared to sprintf.

Comment from the mailing list:

How do I do
    accountNumber = sprintf("%02d-%04d-%08d", [bank, branch, account]);
in Dart?

Isn't
    log("mean=%.2f sd=%.2f", [stats.mean, stats.deviation]);
clearer and hugely more efficient than
    log("mean=${stats.mean.toStringAsFixed(2)} sd=${stats.deviation.toStringAsFixed(2)}");


_Removed Type-Defect, Area-Language labels._
_Added Type-Enhancement, Area-Library, Triaged labels._

_Changed the title to: "Add sprintf function for strings"._

_This comment was originally written by andrew.pennebaker...@gmail.com_


Agreed.

_This comment was originally written by [email protected]_


Hi guys! May I suggest to add something similar to Python string formatting? It's less verbose and quite flexible
e.g.
var goofy = "Goofy";
var mickey = "Mickey Mouse";
var introduce = "May I introduce myself? My name is %s";
print(introduce%goofy); //Print "May I introduce myself? My name is Goofy"
print(introduce%mickey); //Print "May I introduce myself? My name is Mickey Mouse"

_This comment was originally written by naddis...@gmail.com_


Until a native printf makes it into the language, I've written a dart implementation of sprintf: https://github.com/Naddiseo/dart-sprintf

Should work for most format strings, please let me know (on github) if you find a bug.

_This comment was originally written by al21000717...@gmail.com_


Even without sprintf() like functions, adding simple padding options to interpolated output would be extremely useful.

Something like "${10:expr}" or even "${a,b,c:expr}" (where "a,b,c" are formatting options/modifiers) - the syntax should be unambiguous enough in this context.

_This comment was originally written by IanDavidKer...@gmail.com_


An alternative I've just seen on the Scala website (http://docs.scala-lang.org/overviews/core/string-interpolation.html) shows how you can mix interpolation with sprintf formatting.

We'd need to slightly change the Scala syntax to use a different character than '%' to start the format, say '#' as '%' is modulo divide.

var height = 1.9;
var name = "Fred";
print("$name is $height#颅2.2f meters tall"); // "Fred is 1.90 meters"

var hex = 255;
print("$hex#颅08x");

Or with expressions: -
print("255 = $hex#颅08x hex"); // "255 = FF hex"

_This comment was originally written by IanDavi...@gmail.com_


Oops. I'd also say it would be good to use an extended sprintf format for date and time formatting, i.e. fields for the component parts but also a locale-aware short/medium/long date indicator.

I found myself wanting to use formatting like "%02x" today and had a sad-face moment when I came here.

_This comment was originally written by tiago...@gmail.com_


Indeed. A bit disappointed dart reached 1.0 without this. Issue starred! :)

_This comment was originally written by jirkad...@gmail.com_


Formatting strings are so 1980. What about having the Dart version take a
reusable formatting object, like sprintf(Format.literalString('My name is
') + Format.decimal()..length=2..padWith(' ')..align=Format.left, [name]);

justsaying

_This comment was originally written by tiagosousa...@gmail.com_


@#颅14 One word: verbosity. Sprintf may be old school but it's a very compact way of making common and useful formats. I'm not against the existance of other formatting tools but this one is a de-facto standard in programming languages both classic and modern.

_This comment was originally written by ant...@antonmoiseev.com_


One more case when string formatting is helpful is when your strings separated from the code that actually uses them. Imagine the situation when you have a file with formatted string constants (user notifications, log messages, etc.) and want to replace placeholders with the actual data. String interpolation doesn't help here.

_This comment was originally written by andrew.penne...@gmail.com_


Formatting strings are so 1980. What about having the Dart version take a
reusable formatting object, like sprintf(Format.literalString('My name is
') + Format.decimal()..length=2..padWith(' ')..align=Format.left, [name]);

Jesus Christ, that's verbose! I guess conciseness is a dead art.

String formatting is not same as string interpolation. There are several use cases that can not be achieved using string interpolation. Almost all of them stem from the situation where the variable name is not know or defined in the scope where the string format is defined.

It is sad if we have to come here and explain the difference between the two.

Any news on this? String interpolation isn't very helpful when the strings are provided dynamically by a server, such as in a translation mechanism.

Looks like this might be a request for adding some template function somewhere, e.g.,

String sprintf(String template, List<Object> arguments) {
  String result = "";
  int argumentsIndex = 0;
  for (int index = 0; index < template.length; index++) {
    if (template.codeUnitAt(index) == 37 /* ascii '%' */) {
      result += arguments[argumentsIndex++].toString();
    } else {
      result += template.substring(index, index+1);
    }
  }
  return result;
}

OK, that's a completely stupid implementation, but it's just to reduce this issue to "implement this for real".

Apart from the fact that it would be nice to have support for all the C-like specifiers (%8.3f and such), I can't see why this couldn't be just another package, and anyone who wants it could help getting it implemented (the cost would then be import 'package:sprintf/sprintf.dart';).

Sorry, should have checked! ;-)

Things like localized strings really benefit from string formatting support, too. Sentence structure and word order is completely different in different languages, so being able to put a placeholder in a string for something like a name makes it much easier.

i.e. var finalString = String.format(myLocalizedString, userName);
So, if myLocalizedString is something like "Welcome {0}", then the result of the above might be something like: "Welcome Derek" in English, but something different in another language, but the translator can put the placeholder in the right place according to the relevant sentence structure for that language.

@dereklakin
What you mentioned is the exact reason why i came to this page.
It's much easier to have this feature as 'built-in' rather than needing to install external packages.

For me when i tried to install 'sprintf' i had an error, but i changed my mind once i've got that error, i said to myself [ I won't install a library instead of writing a single function with few lines ]

Terrible. A simple variable arguments list implementation issue, the discussion take a so long time. from 2012 to now. I am frustrated

As you correctly point out, Dart does not have var-args, which is one of the reasons for not having a sprintf function.

Another reason is that it is rarely needed because of string interpolations.

Yes, it's longer to write

"Price: ${x.toStringAsFixed(3)} USD"

than

"Price: %3d USD".format([x])

but not that much in practice.
You can introduce helper functions for the formats you use the most, like

String d(double value, int minLength, [int maxLength]) =>
    (maxLength == null ? "$value" : value.toStringAsFixed(maxLength)).padLeft(minLength, " ");

then you can just write "Price: ${d(x, 3, 3)} USD". The flexibility you get from using any expression, allowing you to use any function you can dream up, along with the locality and type-safeness of doing the formatting directly on the value, more than outweighs the conciseness of a format string to me.

The one thing that interpolations cannot do is abstracting over the format. You cannot switch between two format strings, and supply the same arguments to them. To do that in Dart, you would instead introduce a function like (String a, double b) => "foo ${a.padLeft(5, ".")} bar ${b.toStringAsFixed(3)} baz";. That has the added advantage over format strings that it is typed, and (compared to C-style format strings) it allows you to use the arguments in any order.

It's also vastly more efficient. You have to do the same formatting operations to get to the final string, but you can skip parsing the format string. Parsing a string is generally a very expensive operation.

String interpolation does not solve the same problem set as sprintf. Although interpolation is a superior solution to static string formatting, it cannot be used for dynamic string formatting. Every other language I commonly use has dynamic string formatting, likely because developers need such functionality. Why is there such resistance to including support for this in dart core?

I quite agree that this should be implemented in dart core, similar to other languages
At the same time, I don't understand why dart cannot implement such function

But I don't see the urgency to implement this, as this can be fixed by using sprintf package mentioned in previous comments unless there's any other case that I didn't aware of.

In my localization case, I'd prefer writing a few lines of function to replace string template which is sufficient enough for my app.
I don't need the number formatting and stuff because I can do that before replacing the values in the string template.

Just my 2 cents

I assume that "dynamic string formatting" means that the actual format string is not available at compile-time at all, and is provided as data at run-time. That means that you cannot create a function to do the formatting because that also requires the format to be known at compile-time. It is necessarily dynamically typed code since the requirements are not known at compile-time.

That's also a very specific use-case. Most formatting in C programs use a statically known string, and the compilers even validate the arguments against the known string. Most Dart packages do not need dynamic formatting, and can use the (well typed) interpolations instead.

To support dynamic formatting, I am not worried about relying on a package instead of having it in the platform libraries. That allows competing formatting packages to exist, without canonicalizing a single format. That's an advantage, because I don't actually think that there is a single format which is superior.
It does mean that users need to make a choice (which formats to support, which package to use). That's no different from any other number of choices you need to do when picking frameworks for a larger application.

Not currently planned for the platform libraries, or for a separate package.

a 7 year long issue not bad ;-)

I'm currently trying to setup a string for the base URL of one of my API endpoints.

String url = "/sources/$sourceId/comments";

Since I want to define this as the URL for all endpoint calls, get, get_all, insert, I want to set that URL up during object construction, then just provide the sourceId for each API call method as an argument. Clearly the above approach doesn't work with Dart's interpolation, and a string format is what is needed. I know I can just use concatenation but a string format is much more pleasant on the eyes.

This thread is kind of a joke isn't it.

I wrote the format() function like in Python.
See and test: https://pub.dev/packages/format.

'{:.2f}'.format([n]);
'{} {} {}'.format([1, 2, 3]); // 1 2 3
'{2} {1} {0}'.format([1, 2, 3]); // 3 2 1
'{a} {b} {c}'.format([], {'a': 1, 'b': 2, 'c': 3}); // 3 2 1

Python's docs

Was this page helpful?
0 / 5 - 0 ratings