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.