Названные заполнители в строковом форматировании

URL должен выглядеть следующим образом:

http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz

У вас есть обратная косая черта после mnist, поэтому его следует интерпретировать как вкладку.

152
задан Donald Duck 27 November 2017 в 22:33
поделиться

6 ответов

Спасибо за вашу помощь! Используя все ваши подсказки, я написал процедуру, которая делает именно то, что я хочу - форматирование строк в стиле Python с использованием словаря. Поскольку я новичок в Java, приветствуются любые подсказки.

public static String dictFormat(String format, Hashtable<String, Object> values) {
    StringBuilder convFormat = new StringBuilder(format);
    Enumeration<String> keys = values.keys();
    ArrayList valueList = new ArrayList();
    int currentPos = 1;
    while (keys.hasMoreElements()) {
        String key = keys.nextElement(),
        formatKey = "%(" + key + ")",
        formatPos = "%" + Integer.toString(currentPos) + "$";
        int index = -1;
        while ((index = convFormat.indexOf(formatKey, index)) != -1) {
            convFormat.replace(index, index + formatKey.length(), formatPos);
            index += formatPos.length();
        }
        valueList.add(values.get(key));
        ++currentPos;
    }
    return String.format(convFormat.toString(), valueList.toArray());
}
8
ответ дан 23 November 2019 в 22:11
поделиться

Нет ничего встроенного в Java во время записи этого. Я предложил бы писать Вашу собственную реализацию. Мое предпочтение для простого быстрого интерфейса разработчика вместо того, чтобы создать карту и передать его для функционирования - Вы заканчиваете с хорошим непрерывным блоком кода, например:

String result = new TemplatedStringBuilder("My name is {{name}} and I from {{town}}")
   .replace("name", "John Doe")
   .replace("town", "Sydney")
   .finish();

Вот простая реализация:

class TemplatedStringBuilder {

    private final static String TEMPLATE_START_TOKEN = "{{";
    private final static String TEMPLATE_CLOSE_TOKEN = "}}";

    private final String template;
    private final Map<String, String> parameters = new HashMap<>();

    public TemplatedStringBuilder(String template) {
        if (template == null) throw new NullPointerException();
        this.template = template;
    }

    public TemplatedStringBuilder replace(String key, String value){
        parameters.put(key, value);
        return this;
    }

    public String finish(){

        StringBuilder result = new StringBuilder();

        int startIndex = 0;

        while (startIndex < template.length()){

            int openIndex  = template.indexOf(TEMPLATE_START_TOKEN, startIndex);

            if (openIndex < 0){
                result.append(template.substring(startIndex));
                break;
            }

            int closeIndex = template.indexOf(TEMPLATE_CLOSE_TOKEN, openIndex);

            if(closeIndex < 0){
                result.append(template.substring(startIndex));
                break;
            }

            String key = template.substring(openIndex + TEMPLATE_START_TOKEN.length(), closeIndex);

            if (!parameters.containsKey(key)) throw new RuntimeException("missing value for key: " + key);

            result.append(template.substring(startIndex, openIndex));
            result.append(parameters.get(key));

            startIndex = closeIndex + TEMPLATE_CLOSE_TOKEN.length();
        }

        return result.toString();
    }
}
0
ответ дан 23 November 2019 в 22:11
поделиться

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

alt text

1
ответ дан 23 November 2019 в 22:11
поделиться

не совсем, но вы можете использовать MessageFormat для многократного обращения к одному значению:

MessageFormat.format("There's an incorrect value \"{0}\" in column # {1}", x, y);

Вышеописанное можно сделать и с помощью String.format(), но я нахожу синтаксис messageFormat более чистым, если вам нужно строить сложные выражения, плюс вам не нужно заботиться о типе объекта, который вы помещаете в строку

65
ответ дан 23 November 2019 в 22:11
поделиться

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

/**
 * 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
ответ дан 23 November 2019 в 22:11
поделиться

Вы можете использовать библиотеку StringTemplate, она предлагает то, что вы хотите, и многое другое.

import org.antlr.stringtemplate.*;

final StringTemplate hello = new StringTemplate("Hello, $name$");
hello.setAttribute("name", "World");
System.out.println(hello.toString());
15
ответ дан 23 November 2019 в 22:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: