Именованные заполнители в форматировании строки - PullRequest
137 голосов
/ 18 февраля 2010

В Python, когда форматирую строку, я могу заполнять заполнители по имени, а не по позиции, например:

print "There's an incorrect value '%(value)s' in column # %(column)d" % \
  { 'value': x, 'column': y }

Интересно, возможно ли это на Java (надеюсь, без внешних библиотек)?

Ответы [ 15 ]

1 голос
/ 14 мая 2018

Метод Apache Commons Lang replaceEach может пригодиться в зависимости от ваших конкретных потребностей. Вы можете легко использовать его для замены заполнителей по имени с помощью одного вызова метода:

StringUtils.replaceEach("There's an incorrect value '%(value)' in column # %(column)",
            new String[] { "%(value)", "%(column)" }, new String[] { x, y });

При наличии некоторого входного текста это заменит все вхождения заполнителей в первом массиве строк соответствующими значениями во втором.

1 голос
/ 05 сентября 2015

На основе ответа Я создал MapBuilder класс:

public class MapBuilder {

    public static Map<String, Object> build(Object... data) {
        Map<String, Object> result = new LinkedHashMap<>();

        if (data.length % 2 != 0) {
            throw new IllegalArgumentException("Odd number of arguments");
        }

        String key = null;
        Integer step = -1;

        for (Object value : data) {
            step++;
            switch (step % 2) {
                case 0:
                    if (value == null) {
                        throw new IllegalArgumentException("Null key value");
                    }
                    key = (String) value;
                    continue;
                case 1:
                    result.put(key, value);
                    break;
            }
        }

        return result;
    }

}

Затем я создал класс StringFormat для форматирования строк:

public final class StringFormat {

    public static String format(String format, Object... args) {
        Map<String, Object> values = MapBuilder.build(args);

        for (Map.Entry<String, Object> entry : values.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            format = format.replace("$" + key, value.toString());
        }

        return format;
    }

}

который вы можете использовать так:

String bookingDate = StringFormat.format("From $startDate to $endDate"), 
        "$startDate", formattedStartDate, 
        "$endDate", formattedEndDate
);
1 голос
/ 03 сентября 2015

Мой ответ:

а) используйте StringBuilder, когда это возможно

b) сохранить (в любой форме: целое число является лучшим, специальный символ, такой как макрос доллара и т. Д.) В позиции "заполнителя", а затем использовать StringBuilder.insert() (несколько версий аргументов).

Использование внешних библиотек кажется излишним, и я полагаю, что значительное снижение производительности происходит, когда StringBuilder внутренне преобразуется в String.

1 голос
/ 18 февраля 2010

У вас может быть что-то подобное в классе помощников строк

/**
 * An interpreter for strings with named placeholders.
 *
 * For example given the string "hello %(myName)" and the map <code>
 *      <p>Map<String, Object> map = new HashMap<String, Object>();</p>
 *      <p>map.put("myName", "world");</p>
 * </code>
 *
 * the call {@code format("hello %(myName)", map)} returns "hello world"
 *
 * It replaces every occurrence of a named placeholder with its given value
 * in the map. If there is a named place holder which is not found in the
 * map then the string will retain that placeholder. Likewise, if there is
 * an entry in the map that does not have its respective placeholder, it is
 * ignored.
 *
 * @param str
 *            string to format
 * @param values
 *            to replace
 * @return formatted string
 */
public static String format(String str, Map<String, Object> values) {

    StringBuilder builder = new StringBuilder(str);

    for (Entry<String, Object> entry : values.entrySet()) {

        int start;
        String pattern = "%(" + entry.getKey() + ")";
        String value = entry.getValue().toString();

        // Replace every occurence of %(key) with value
        while ((start = builder.indexOf(pattern)) != -1) {
            builder.replace(start, start + pattern.length(), value);
        }
    }

    return builder.toString();
}
1 голос
/ 18 февраля 2010

Попробуйте Freemarker , библиотека шаблонов.

alt text

...