Replace all occurrences with the properties of an object
You can do it in one loop instead of getting all the indexes separately. Just off the top of my head:

        string str = "Your invoice [%InvoiceNo%] will be due on [%DueDate%]";

        int startIndex = 0;

        while ((startIndex = str.IndexOf("[%", startIndex)) &gt; -1)
        {
            int endIndex = str.IndexOf("%]", startIndex);
            string exp = str.Substring(startIndex, endIndex - startIndex + 2);
            string field = str.Substring(startIndex + 2, endIndex - startIndex - 2);
            str = str.Replace(exp, invoice.GetValueByName(field).ToString());
            startIndex = 0;
        }


Some points to note here:


I assume you are guaranteed to see the %] if you find the [%
I didn't test for edge cases like what if str = "[%invoice%]"


This is a neat solution but the more I think about your problem the more I wonder if you can engineer it so you pass what fields you want to your invoice object and it just returns you the correct string so you don't need to mess around with placeholders... food for thought :)