In the communities a users
asked about a way to make a dynamic strFmt call, not knowing the number of parameters up front.
With some good critical tests from
Levgen Miroshnikov (
blog) I think I have managed to write a class method that does that.
Regular StrFmt will round decimal value and change the decimal point to whatever fits your windows locale. This method has a parameter allowing you to keep the formatting of decimal values.
Here is the code for it:
public str dynamicStrFmt(
str _expression,
container _args = conNull(),
boolean _keepRealsDecimals = false)
{
str ret;
Counter counter;
str argStr;
char argChar;
if (_args == conNull())
{
return strFmt(_expression);
}
for (counter = 1; counter <= strLen(_expression); counter++)
{
if (subStr(_expression, counter, 1) != '%')
{
ret += subStr(_expression, counter, 1);
}
else
{
// This is a point in the string where an argument starts
// Find the end of the argument
argStr = '';
argChar = subStr(_expression, counter + 1, 1);
while (argChar && argChar == strKeep(argChar, '0123456789'))
{
argStr += argChar;
argChar = subStr(_expression, counter + strLen(argStr) + 1, 1);
}
// Lookup and insert the value to the result
if (argStr)
{
// Check that the argument is within the bounds of the number of supplied argument values
if (str2Int(argStr) <= conLen(_args))
{
if (typeOf(conPeek(_args, str2Int(argStr))) == Types::Real && _keepRealsDecimals)
{
ret += num2str(conPeek(_args, str2Int(argStr)), -1, numOfDec(conPeek(_args, str2Int(argStr))), 1, 0);
}
else
{
ret += strFmt('%1', conPeek(_args, str2Int(argStr)));
}
}
else
{
// The argument is not within the bounds of the supplied argument values. Keep the argument unchanged.
ret += subStr(_expression, counter, 1) + argStr;
}
// Move the current position in the _expression string to a position after the argument
counter += strLen(argStr);
}
else
{
// Didn't find the argument to be meningfull, so just add the argument character as-is
ret += subStr(_expression, counter, 1);
}
}
}
return ret;
}
And a main method for a quick demo:
public static void main(Args _args)
{
aaaStrFmtBuilder demo = new aaaStrFmtBuilder();
info (demo.dynamicStrFmt("%1 + %1 = %2", [2, 4]));
info(demo.dynamicStrFmt("%1/(%2*%1)", [1000, 0.135], true));
info(demo.dynamicStrFmt("%2 %3 %1", ['AX', 'Microsoft', 'Dynamics']));
}
And here you can download a project with the class and unit tests for it:
The two classes are prefixed with 'aaa', making it easier for you to find them in the AOT :-)
Please change the names if you are going to use the code for something real.