Improvement of format string. Re: Suggestion for a D project/std module: templated format

renoX renosky at free.fr
Wed Feb 21 06:34:45 PST 2007


Miles Wrote:

> Derek Parnell wrote:
> > For what its worth, I tend to just use '%s' in writefln() calls, and almost
> > never use any of the other format codes, regardless of the data type being
> > supplied in the arguments.

Yes, %s and the like are useless except when you need a special format like %08d.

In Ruby, they provide an escape syntax 'puts "test #{variable}"' without format for the default embedding.

IMHO in D we could use a similar syntax: writef("text %{variable}"); and writef("test %08d{variable2}"); the %{} embedded in the strings helps a lot readability I think.

Below is a sample implementation (could be used as a basis for "templated format" if wanted), it is lacking the possibility to have %08d{} but this could be added..

renoX

import std.stdio;

template FindChar(char[] A, char B) {
    static if (A.length == 0) {
        const int FindChar = -1;
    } else static if (A[0] == B) {
        const int FindChar = 0;
    } else static if (-1 == FindChar!(A[1..$], B)) {
		const int FindChar = -1;
	} else {
		const int FindChar = 1 + FindChar!(A[1..$], B);
	}
}

template FmtString(char[] F, A...)
{
    static if (F.length == 0)
		static if (A.length)
			const char[] FmtString = "\"," ~ Fmt!(A);
		else
			const char[] FmtString = "\"";
    else static if (F.length == 1)
		static if (A.length)
			const char[] FmtString = F[0] ~ "\"," ~ Fmt!(A);
		else
			const char[] FmtString = F[0] ~ "\"";
    else static if (F[0..2] == "%{")
	{
		// get the variable name between %{ and }
		static if (FindChar!(F[2..$], '}') <= 0)
			static assert(0, "format %{ incorrect in '" ~ F ~ "'");
		const char[] FmtString = "%s\"," ~ F[2..2+FindChar!(F[2..$],'}')] ~ ",\"" ~ 
			FmtString!(F[3+FindChar!(F[2..$],'}')..$], A);
	}
    else static if (F[0..2] == "%%")
		const char[] FmtString = "%%" ~ FmtString!(F[2..$], A);
//    else static if (F[0] == '%')
//		static assert(0, "unrecognized Fmt '%" ~ F[1] ~ "'");
    else
		const char[] FmtString = F[0] ~ FmtString!(F[1..$], A);
}

template Fmt(A...)
{
    static if (A.length == 0)
		const char[] Fmt = "";
    else static if (is(typeof(A[0]) : char[]))
		const char[] Fmt = "\"" ~ FmtString!(A[0], A[1..$]);
    else static if (A.length == 1)
		const char[] Fmt = A[0].stringof;
	else
		const char[] Fmt = A[0].stringof ~ "," ~ Fmt!(A[1..$]);	
}

template Putf(A...)
{
	const char[] Putf = "writef(" ~ Fmt!(A) ~ ");";
//	static assert(0, Putf);
}


int main()
{
	int x = 10;
	int y = 20;
	
	writef("BEFORE'");
	mixin(Putf!("foo",x));
	writef("'AFTER\n");

	writef("BEFORE'");
	mixin(Putf!("foo",x,y));
	writef("'AFTER\n");
	

	writef("BEFORE'");
	mixin(Putf!(x,"foo"));
	writef("'AFTER\n");

	writef("BEFORE'");
	mixin(Putf!(x));
	writef("'AFTER\n");
	
	writef("BEFORE'");
	mixin(Putf!("foo\n"));
	writef("'AFTER\n");
	
	writef("BEFORE'");
	mixin(Putf!("test avant %%{x} apres"));
	writef("'AFTER\n");

	writef("BEFORE'");
	mixin(Putf!("test avant %{x} apres"));
	writef("'AFTER\n");

	char[] text="should see the % in %{x}";
	
	writef("BEFORE'");
	mixin(Putf!("test avant %{text} apres"));
	writef("'AFTER\n");
	
	writef("BEFORE'");
	mixin(Putf!("test avant %{text} apres %{x} encore apres"));
	writef("'AFTER\n");
	
	writef("BEFORE'");
	mixin(Putf!("test avant", "apres\n"));
	writef("'AFTER\n");

	
	writef("BEFORE'");
	mixin(Putf!("test avant %{text}"," apres %{x} encore apres"));
	writef("'AFTER\n");

	writef("BEFORE'");
	mixin(Putf!("test avant %{text}"," apres %{x} encore apres ",x));
	writef("'AFTER\n"); 

	return 0;
}




More information about the Digitalmars-d mailing list