1 /* 2 * Copyright (c) 2004-2007 QOS.ch 3 * All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 package org.slf4j.helpers; 26 27 28 /** 29 * Formats messages according to very simple substitution rules. Substitutions can be 30 * made 1, 2 or more arguments. 31 * <p> 32 * For example, 33 * <pre>MessageFormatter.format("Hi {}.", "there");</pre> will 34 * return the string "Hi there.". 35 * <p> 36 * The {} pair is called the <em>formatting anchor</em>. It serves to designate the 37 * location where arguments need to be substituted within the message pattern. 38 * <p> 39 * In the rare case where you need to place the '{' or '}' in the message pattern 40 * itself but do not want them to be interpreted as a formatting anchors, you can 41 * espace the '{' character with '\', that is the backslash character. Only the 42 * '{' character should be escaped. There is no need to escape the '}' character. 43 * For example, <pre>MessageFormatter.format("File name is \\{{}}.", "App folder.zip");</pre> 44 * will return the string "File name is {App folder.zip}.". 45 * 46 * See {@link #format(String, Object)}, {@link #format(String, Object, Object)} 47 * and {@link #arrayFormat(String, Object[])} methods for more details. 48 * 49 * @author Ceki Gülcü 50 */ 51 public class MessageFormatter { 52 static final char DELIM_START = '{'; 53 static final char DELIM_STOP = '}'; 54 55 /** 56 * Performs single argument substitution for the 'messagePattern' passed as 57 * parameter. 58 * <p> 59 * For example, <pre>MessageFormatter.format("Hi {}.", "there");</pre> will 60 * return the string "Hi there.". 61 * <p> 62 * @param messagePattern The message pattern which will be parsed and formatted 63 * @param argument The argument to be substituted in place of the formatting anchor 64 * @return The formatted message 65 */ 66 public static String format(String messagePattern, Object arg) { 67 return arrayFormat(messagePattern, new Object[] {arg}); 68 } 69 70 /** 71 * 72 * Performs a two argument substitution for the 'messagePattern' passed as 73 * parameter. 74 * <p> 75 * For example, 76 * <pre>MessageFormatter.format("Hi {}. My name is {}.", "Alice", "Bob");</pre> will 77 * return the string "Hi Alice. My name is Bob.". 78 * 79 * @param messagePattern The message pattern which will be parsed and formatted 80 * @param arg1 The argument to be substituted in place of the first formatting anchor 81 * @param arg2 The argument to be substituted in place of the second formatting anchor 82 * @return The formatted message 83 */ 84 public static String format(String messagePattern, Object arg1, Object arg2) { 85 return arrayFormat(messagePattern, new Object[] {arg1, arg2}); 86 } 87 88 /** 89 * Same principle as the {@link #format(String, Object)} and 90 * {@link #format(String, Object, Object)} methods except that 91 * any number of arguments can be passed in an array. 92 * 93 * @param messagePattern The message pattern which will be parsed and formatted 94 * @param argArray An array of arguments to be substituted in place of formatting anchors 95 * @return The formatted message 96 */ 97 public static String arrayFormat(String messagePattern, Object[] argArray) { 98 if(messagePattern == null) { 99 return null; 100 } 101 int i = 0; 102 int len = messagePattern.length(); 103 int j = messagePattern.indexOf(DELIM_START); 104 105 106 107 StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50); 108 109 for (int L = 0; L < argArray.length; L++) { 110 111 char escape = 'x'; 112 113 j = messagePattern.indexOf(DELIM_START, i); 114 115 if (j == -1 || (j+1 == len)) { 116 // no more variables 117 if (i == 0) { // this is a simple string 118 return messagePattern; 119 } else { // add the tail string which contains no variables and return the result. 120 sbuf.append(messagePattern.substring(i, messagePattern.length())); 121 return sbuf.toString(); 122 } 123 } else { 124 char delimStop = messagePattern.charAt(j + 1); 125 if (j > 0) { 126 escape = messagePattern.charAt(j - 1); 127 } 128 129 if(escape == '\\') { 130 L--; // DELIM_START was escaped, thus should not be incremented 131 sbuf.append(messagePattern.substring(i, j-1)); 132 sbuf.append(DELIM_START); 133 i = j + 1; 134 } else if ((delimStop != DELIM_STOP)) { 135 // invalid DELIM_START/DELIM_STOP pair 136 sbuf.append(messagePattern.substring(i, messagePattern.length())); 137 return sbuf.toString(); 138 } else { 139 // normal case 140 sbuf.append(messagePattern.substring(i, j)); 141 sbuf.append(argArray[L]); 142 i = j + 2; 143 } 144 } 145 } 146 // append the characters following the second {} pair. 147 sbuf.append(messagePattern.substring(i, messagePattern.length())); 148 return sbuf.toString(); 149 } 150 }