[slf4j-dev] svn commit: r953 - in slf4j/trunk/slf4j-api/src: main/java/org/slf4j/helpers test/java/org/slf4j/helpers

ceki at slf4j.org ceki at slf4j.org
Tue Jan 29 20:19:00 CET 2008


Author: ceki
Date: Tue Jan 29 20:19:00 2008
New Revision: 953

Modified:
   slf4j/trunk/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java
   slf4j/trunk/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java

Log:
- fixing bug 61.


Modified: slf4j/trunk/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java
==============================================================================
--- slf4j/trunk/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java	(original)
+++ slf4j/trunk/slf4j-api/src/main/java/org/slf4j/helpers/MessageFormatter.java	Tue Jan 29 20:19:00 2008
@@ -24,30 +24,38 @@
 
 package org.slf4j.helpers;
 
-
 /**
-  * Formats messages according to very simple substitution rules. Substitutions can be
-  * made 1, 2 or more arguments.
-  * <p>
-  * For example, 
-  * <pre>MessageFormatter.format("Hi {}.", "there");</pre> will
-  * return the string "Hi there.".
-  * <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>
-  * 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
-  * espace 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("File name is \\{{}}.", "App folder.zip");</pre>
-  * will return the string "File name is {App folder.zip}.". 
-  * 
-  * See {@link #format(String, Object)}, {@link #format(String, Object, Object)} 
-  * and {@link #arrayFormat(String, Object[])} methods for more details.
-  *
-  * @author Ceki G&uuml;lc&uuml;
-  */
+ * Formats messages according to very simple substitution rules. Substitutions
+ * can be made 1, 2 or more arguments.
+ * <p>
+ * For example,
+ * <pre>MessageFormatter.format(&quot;Hi {}.&quot;, &quot;there&quot;);</pre>
+ * will return the string "Hi there.".
+ * <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>
+ * 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 espace 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 \\{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>
+ * The escaping behaviour just described can be overridden by 
+ * escaping the escape character '\'. Calling
+ * <pre>MessageFormatter.format(&quot;File name is C:\\\\{}.&quot;, &quot;file.zip&quot;);</pre>
+ * will return the string "File name is C:\file.zip".
+ * 
+ * <p>
+ * See {@link #format(String, Object)}, {@link #format(String, Object, Object)}
+ * and {@link #arrayFormat(String, Object[])} methods for more details.
+ * 
+ * @author Ceki G&uuml;lc&uuml;
+ */
 public class MessageFormatter {
   static final char DELIM_START = '{';
   static final char DELIM_STOP = '}';
@@ -56,81 +64,104 @@
    * Performs single argument substitution for the 'messagePattern' passed as
    * parameter.
    * <p>
-   * For example, <pre>MessageFormatter.format("Hi {}.", "there");</pre> will
-   * return the string "Hi there.".
+   * For example,
+   * 
+   * <pre>
+   * MessageFormatter.format(&quot;Hi {}.&quot;, &quot;there&quot;);
+   * </pre>
+   * 
+   * will return the string "Hi there.".
    * <p>
-   * @param messagePattern The message pattern which will be parsed and formatted
-   * @param argument The argument to be substituted in place of the formatting anchor
+   * 
+   * @param messagePattern
+   *          The message pattern which will be parsed and formatted
+   * @param argument
+   *          The argument to be substituted in place of the formatting anchor
    * @return The formatted message
    */
   public static String format(String messagePattern, Object arg) {
-    return arrayFormat(messagePattern, new Object[] {arg});   
-   }
-  
+    return arrayFormat(messagePattern, new Object[] { arg });
+  }
+
   /**
-   *
+   * 
    * Performs a two argument substitution for the 'messagePattern' passed as
    * parameter.
    * <p>
-   * For example, 
-   * <pre>MessageFormatter.format("Hi {}. My name is {}.", "Alice", "Bob");</pre> will 
-   * return the string "Hi Alice. My name is Bob.".
-   * 
-   * @param messagePattern The message pattern which will be parsed and formatted
-   * @param arg1 The argument to be substituted in place of the first formatting anchor 
-   * @param arg2 The argument to be substituted in place of the second formatting anchor 
+   * For example,
+   * 
+   * <pre>
+   * MessageFormatter.format(&quot;Hi {}. My name is {}.&quot;, &quot;Alice&quot;, &quot;Bob&quot;);
+   * </pre>
+   * 
+   * will return the string "Hi Alice. My name is Bob.".
+   * 
+   * @param messagePattern
+   *          The message pattern which will be parsed and formatted
+   * @param arg1
+   *          The argument to be substituted in place of the first formatting
+   *          anchor
+   * @param arg2
+   *          The argument to be substituted in place of the second formatting
+   *          anchor
    * @return The formatted message
    */
   public static String format(String messagePattern, Object arg1, Object arg2) {
-   return arrayFormat(messagePattern, new Object[] {arg1, arg2});   
+    return arrayFormat(messagePattern, new Object[] { arg1, arg2 });
   }
-  
+
   /**
-   * Same principle as the {@link #format(String, Object)} and 
-   * {@link #format(String, Object, Object)} methods except that
-   * any number of arguments can be passed in an array.
+   * Same principle as the {@link #format(String, Object)} and
+   * {@link #format(String, Object, Object)} methods except that any number of
+   * arguments can be passed in an array.
    * 
-   * @param messagePattern The message pattern which will be parsed and formatted
-   * @param argArray An array of arguments to be substituted in place of formatting anchors
+   * @param messagePattern
+   *          The message pattern which will be parsed and formatted
+   * @param argArray
+   *          An array of arguments to be substituted in place of formatting
+   *          anchors
    * @return The formatted message
    */
   public static String arrayFormat(String messagePattern, Object[] argArray) {
-    if(messagePattern == null) {
+    if (messagePattern == null) {
       return null;
     }
     int i = 0;
     int len = messagePattern.length();
     int j = messagePattern.indexOf(DELIM_START);
-    
-  
-    
+
     StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50);
 
     for (int L = 0; L < argArray.length; L++) {
-      
-      char escape = 'x';
-      
+
       j = messagePattern.indexOf(DELIM_START, i);
 
-      if (j == -1 || (j+1 == len)) {
+      if (j == -1 || (j + 1 == len)) {
         // no more variables
         if (i == 0) { // this is a simple string
           return messagePattern;
-        } else { // add the tail string which contains no variables and return the result.
+        } else { // add the tail string which contains no variables and return
+          // the result.
           sbuf.append(messagePattern.substring(i, messagePattern.length()));
           return sbuf.toString();
         }
       } else {
         char delimStop = messagePattern.charAt(j + 1);
-        if (j > 0) {
-          escape = messagePattern.charAt(j - 1);
-        }
-        
-        if(escape == '\\') {
-          L--; // DELIM_START was escaped, thus should not be incremented
-          sbuf.append(messagePattern.substring(i, j-1));
-          sbuf.append(DELIM_START);
-          i = j + 1;
+
+        if (isEscapedDelimeter(messagePattern, j)) {
+          if(!isDoubleEscaped(messagePattern, j)) {
+            L--; // DELIM_START was escaped, thus should not be incremented
+            sbuf.append(messagePattern.substring(i, j - 1));
+            sbuf.append(DELIM_START);
+            i = j + 1;
+          } else {
+            // The escape character preceding the delemiter start is
+            // itself escaped: "abc x:\\{}"
+            // we have to consume one backward slash
+            sbuf.append(messagePattern.substring(i, j-1));
+            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()));
@@ -147,4 +178,27 @@
     sbuf.append(messagePattern.substring(i, messagePattern.length()));
     return sbuf.toString();
   }
+
+  static boolean isEscapedDelimeter(String messagePattern,
+      int delimeterStartIndex) {
+
+    if (delimeterStartIndex == 0) {
+      return false;
+    }
+    char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
+    if (potentialEscape == '\\') {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {
+    if (delimeterStartIndex >= 2
+        && messagePattern.charAt(delimeterStartIndex - 2) == '\\') {
+      return true;
+    } else {
+      return false;
+    }
+  }
 }

Modified: slf4j/trunk/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java
==============================================================================
--- slf4j/trunk/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java	(original)
+++ slf4j/trunk/slf4j-api/src/test/java/org/slf4j/helpers/MessageFormatterTest.java	Tue Jan 29 20:19:00 2008
@@ -80,7 +80,7 @@
   }
   
   
-  public void test1Param() {
+  public void testOneParameter() {
     String result;
     
     result = MessageFormatter.format("Value is {}.", i3);
@@ -98,6 +98,9 @@
     result = MessageFormatter.format("Incorrect {subst", i3);
     assertEquals("Incorrect {subst", result);
     
+    result = MessageFormatter.format("Value is \\{bla} {}", i3);
+    assertEquals("Value is {bla} 3", result);
+    
     result = MessageFormatter.format("Escaped \\{} subst", i3);
     assertEquals("Escaped {} subst", result);
 
@@ -109,9 +112,13 @@
     
     result = MessageFormatter.format("File name is \\{{}}.", "App folder.zip");
     assertEquals("File name is {App folder.zip}.", result);
+    
+    // escaping the escape character
+    result = MessageFormatter.format("File name is C:\\\\{}.", "App folder.zip");
+    assertEquals("File name is C:\\App folder.zip.", result);
   }
   
-  public void test2Param() {
+  public void testTwoParameters() {
     String result;
 
     



More information about the slf4j-dev mailing list