Parameter substitution code has been simplified. SLF4J now only
cares about the "{}" formatting anchor, that is the '{' character
immediately followed by '}'. Previously, the '{' had meaning on its
own. As a result of this change, users no longer need to escape the
'{' unless it is immediately followed by '}'. Existing messages
which escaped standalone '{' character will be printed with a
preceding backslash. However, no data loss in the printed messages
will occur.

The new code also runs about 5% faster.
diff --git a/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java b/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java
index 96408e6..35fcbad 100644
--- a/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java
+++ b/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java
@@ -35,9 +35,7 @@
  * <p>

  * For example,

  * 

- * <pre>

- * MessageFormatter.format(&quot;Hi {}.&quot;, &quot;there&quot;);

- * </pre>

+ * <pre>MessageFormatter.format(&quot;Hi {}.&quot;, &quot;there&quot;)</pre>

  * 

  * will return the string "Hi there.".

  * <p>

@@ -45,18 +43,28 @@
  * designate the location where arguments need to be substituted within the

  * message pattern.

  * <p>

- * In the rare case where you need to place the '{' or '}' in the message

- * pattern itself but do not want them to be interpreted as a formatting

- * anchors, you can escape the '{' character with '\', that is the backslash

- * character. Only the '{' character should be escaped. There is no need to

- * escape the '}' character. For example,

+ * In case your message contains the '{' or the '}' character, you do not have

+ * to do anything special unless the '}' character immediately follows '}'. For

+ * example,

  * 

  * <pre>

- * MessageFormatter.format(&quot;Set \\{1,2,3} is not equal to {}.&quot;, &quot;1,2&quot;);

+ * MessageFormatter.format(&quot;Set {1,2,3} is not equal to {}.&quot;, &quot;1,2&quot;);

  * </pre>

  * 

  * will return the string "Set {1,2,3} is not equal to 1,2.".

  * 

+ * <p>If for whatever reason you need to place the string "{}" in the message

+ * without its <em>formatting anchor</em> meaning, then you need to escape the

+ * '{' character with '\', that is the backslash character. Only the '{'

+ * character should be escaped. There is no need to escape the '}' character.

+ * For example,

+ * 

+ * <pre>

+ * MessageFormatter.format(&quot;Set \\{} is not equal to {}.&quot;, &quot;1,2&quot;);

+ * </pre>

+ * 

+ * will return the string "Set {} is not equal to 1,2.".

+ * 

  * <p>

  * The escaping behavior just described can be overridden by escaping the escape

  * character '\'. Calling

@@ -73,9 +81,10 @@
  * 

  * @author Ceki G&uuml;lc&uuml;

  */

-public class MessageFormatter {

+final public class MessageFormatter {

   static final char DELIM_START = '{';

   static final char DELIM_STOP = '}';

+  static final String DELIM_STR = "{}";

   private static final char ESCAPE_CHAR = '\\';

 

   /**

@@ -98,7 +107,7 @@
    *                anchor

    * @return The formatted message

    */

-  public static String format(String messagePattern, Object arg) {

+  final public static String format(String messagePattern, Object arg) {

     return arrayFormat(messagePattern, new Object[] { arg });

   }

 

@@ -125,7 +134,7 @@
    *                formatting anchor

    * @return The formatted message

    */

-  public static String format(String messagePattern, Object arg1, Object arg2) {

+  final public static String format(final String messagePattern, Object arg1, Object arg2) {

     return arrayFormat(messagePattern, new Object[] { arg1, arg2 });

   }

 

@@ -141,25 +150,23 @@
    *                formatting anchors

    * @return The formatted message

    */

-  public static String arrayFormat(String messagePattern, Object[] argArray) {

+  final public static String arrayFormat(final String messagePattern,

+      final Object[] argArray) {

     if (messagePattern == null) {

       return null;

     }

-    int i = 0;

-    int len = messagePattern.length();

-    int j = messagePattern.indexOf(DELIM_START);

-

     if (argArray == null) {

       return messagePattern;

     }

-

+    int i = 0;

+    int j;

     StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50);

 

     for (int L = 0; L < argArray.length; L++) {

 

-      j = messagePattern.indexOf(DELIM_START, i);

+      j = messagePattern.indexOf(DELIM_STR, i);

 

-      if (j == -1 || (j + 1 == len)) {

+      if (j == -1) {

         // no more variables

         if (i == 0) { // this is a simple string

           return messagePattern;

@@ -169,8 +176,6 @@
           return sbuf.toString();

         }

       } else {

-        char delimStop = messagePattern.charAt(j + 1);

-

         if (isEscapedDelimeter(messagePattern, j)) {

           if (!isDoubleEscaped(messagePattern, j)) {

             L--; // DELIM_START was escaped, thus should not be incremented

@@ -183,13 +188,8 @@
             // we have to consume one backward slash

             sbuf.append(messagePattern.substring(i, j - 1));

             deeplyAppendParameter(sbuf, argArray[L], new HashMap());

-            // sbuf.append(argArray[L]);

             i = j + 2;

           }

-        } else if ((delimStop != DELIM_STOP)) {

-          // invalid DELIM_START/DELIM_STOP pair

-          sbuf.append(messagePattern.substring(i, messagePattern.length()));

-          return sbuf.toString();

         } else {

           // normal case

           sbuf.append(messagePattern.substring(i, j));

@@ -203,7 +203,7 @@
     return sbuf.toString();

   }

 

-  static boolean isEscapedDelimeter(String messagePattern,

+  final static boolean isEscapedDelimeter(String messagePattern,

       int delimeterStartIndex) {

 

     if (delimeterStartIndex == 0) {

@@ -217,7 +217,7 @@
     }

   }

 

-  static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {

+  final static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {

     if (delimeterStartIndex >= 2

         && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) {

       return true;

diff --git a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java
index a7a2530..ce93f7a 100644
--- a/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java
+++ b/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java
@@ -100,19 +100,19 @@
     result = MessageFormatter.format("Incorrect {subst", i3);

     assertEquals("Incorrect {subst", result);

 

-    result = MessageFormatter.format("Value is \\{bla} {}", i3);

+    result = MessageFormatter.format("Value is {bla} {}", i3);

     assertEquals("Value is {bla} 3", result);

 

     result = MessageFormatter.format("Escaped \\{} subst", i3);

     assertEquals("Escaped {} subst", result);

 

-    result = MessageFormatter.format("\\{Escaped", i3);

+    result = MessageFormatter.format("{Escaped", i3);

     assertEquals("{Escaped", result);

 

     result = MessageFormatter.format("\\{}Escaped", i3);

     assertEquals("{}Escaped", result);

 

-    result = MessageFormatter.format("File name is \\{{}}.", "App folder.zip");

+    result = MessageFormatter.format("File name is {{}}.", "App folder.zip");

     assertEquals("File name is {App folder.zip}.", result);

 

     // escaping the escape character

@@ -147,7 +147,7 @@
     assertEquals("Value 1 is smaller than \\{", result);

 

     result = MessageFormatter

-        .format("Value {} is smaller than \\{tail", i1, i2);

+        .format("Value {} is smaller than {tail", i1, i2);

     assertEquals("Value 1 is smaller than {tail", result);

 

     result = MessageFormatter.format("Value \\{} is smaller than {}", i1, i2);

@@ -195,9 +195,9 @@
     assertEquals("Value 1 is smaller than 2", result);

 

     result = MessageFormatter.arrayFormat("Val={}, {, Val={}", ia0);

-    assertEquals("Val=1, {, Val={}", result);

+    assertEquals("Val=1, {, Val=2", result);

 

-    result = MessageFormatter.arrayFormat("Val={}, \\{, Val={}", ia0);

+    result = MessageFormatter.arrayFormat("Val={}, {, Val={}", ia0);

     assertEquals("Val=1, {, Val=2", result);

 

     result = MessageFormatter.arrayFormat("Val1={}, Val2={", ia0);

diff --git a/slf4j-site/src/site/pages/faq.html b/slf4j-site/src/site/pages/faq.html
index 6cafd12..7af5587 100644
--- a/slf4j-site/src/site/pages/faq.html
+++ b/slf4j-site/src/site/pages/faq.html
@@ -615,8 +615,7 @@
        disabled.

        </p>

        

- 

-       <p>The following two lines will yield the exact same

+        <p>The following two lines will yield the exact same

        output. However, the second form will outperform the first

        form by a factor of at least 30, in case of a

        <em>disabled</em> logging statement.

@@ -644,18 +643,59 @@
         <p></p> 

 

         <p>Array type arguments, including multi-dimensional arrays,

-        are also supported. </p>

-        

+        are also supported.</p>

+

         <p>SLF4J uses its own message formatting implementation which

         differs from that of the Java platform. This is justified by

-        the fact that SLF4J's implementation performs several orders

-        of magnitude faster but at the cost of being non-standard and

-        less flexible.

+        the fact that SLF4J's implementation performs about 10 times

+        faster but at the cost of being non-standard and less

+        flexible.

         </p>

 

-        <p>

+        <p><b>Escaping the "{}" pair</b></p>

+

+        <p>The "{}" pair is called the <em>formatting anchor</em>. It

+        serves to designate the location where arguments need to be

+        substituted within the message pattern.

         </p>

 

+        <p>SLF4J only cares about the <em>formatting anchor</em>, that

+        is the '{' character immediately followed by '}'. Thus, in

+        case your message contains the '{' or the '}' character, you

+        do not have to do anything special unless the '}' character

+        immediately follows '}'. For example,

+        </p>

+

+        <p class="source">logger.debug("Set {1,2} differs from {}", "3");</p>

+        

+        <p>which will print as "Set {1,2} differs from 3". </p>

+        

+        <p>You could have even written,</p>

+        <p class="source">logger.debug("Set {1,2} differs from {{}}", "3");</p>

+        <p>which would have printed as "Set {1,2} differs from {3}". </p>

+

+        <p>In the extremely rare case where the the "{}" pair occurs

+        naturally within your text and you wish to disable the special

+        meaning of the formatting anchor, then you need to escape the

+        '{' character with '\', that is the backslash character. Only

+        the '{' character should be escaped. There is no need to

+        escape the '}' character. For example,

+        </p>

+

+        <p class="source">logger.debug("Set \\{} differs from {}", "3");</p>

+ 

+        <p>will print as "Set {} differs from 3". Note that within

+        Java code, the backslash cracacter needs to be written as

+        '\\'.</p>

+

+        <p>In the rare case where the "\{}' occurs naturally in the

+        message, you can double escape the formatting anchor so that

+        it retains its original meaning. For example,</p>

+

+        

+        <p class="source">logger.debug("File name is C:\\\\{}.", "file.zip");</p>

+        <p>will print as "File name is C:\file.zip".</p>

+

         <hr />

              

         </dd>

diff --git a/slf4j-site/src/site/pages/news.html b/slf4j-site/src/site/pages/news.html
index 5abd31f..ad78958 100644
--- a/slf4j-site/src/site/pages/news.html
+++ b/slf4j-site/src/site/pages/news.html
@@ -62,6 +62,16 @@
   previously. This enhancement was proposed by "lizongbo".

   </p>

 

+  <p>Parameter substitution code has been simplified. SLF4J now only

+  cares about the "{}" formatting anchor, that is the '{' character

+  immediately followed by '}'. Previously, the '{' had meaning on its

+  own. As a result of this change, users no longer need to escape the

+  '{' unless it is immediately followed by '}'. Existing messages

+  which escaped standalone '{' character will be printed with a

+  preceding backslash. However, no data loss in the printed messages

+  will occur.

+  </p>

+

 

   <p>Added missing <code>getInstance</code> methods to the

   <code>Category</code> class in the log4j-over-slf4j module, fixing