Как заменить маркеры в строке без StringTokenizer

Один из способов, которыми Вы используете одиночный элемент, состоит в том, чтобы покрыть экземпляр, где должен быть единственный "брокер", управляющий доступом к ресурсу. Одиночные элементы хороши в регистраторах, потому что они посредничают в доступе к, скажем, файлу, который может только быть записан в исключительно. Для чего-то как вход они дают возможность абстракции далеко записей к чему-то как файл журнала - Вы могли обернуть механизм кэширования к своему одиночному элементу, и т.д.

Также думают о ситуации, где у Вас есть приложение со многими окнами/потоками/и т.д., но которому нужна единственная точка коммуникации. Я когда-то использовал для управления заданиями, которые я хотел, чтобы мое приложение запустило. Одиночный элемент был ответственен за сериализацию заданий и отображение их состояния к любой другой части программы, которой было интересно. В этом виде сценария можно посмотреть на одиночный элемент, как являющийся видом подобных выполнение класса "сервера" в приложении... HTH

9
задан Yishai 16 July 2009 в 16:40
поделиться

10 ответов

Попробуйте следующее:

Примечание: Окончательное решение автора основано на этом примере и является гораздо более кратким.

public class TokenReplacer {

    private Pattern tokenPattern;

    public TokenReplacer() {
        tokenPattern = Pattern.compile("\\{([^}]+)\\}");
    }

    public String replaceTokens(String text, Map<String, String> valuesByKey) {
        StringBuilder output = new StringBuilder();
        Matcher tokenMatcher = tokenPattern.matcher(text);

        int cursor = 0;
        while (tokenMatcher.find()) {
            // A token is defined as a sequence of the format "{...}".
            // A key is defined as the content between the brackets.
            int tokenStart = tokenMatcher.start();
            int tokenEnd = tokenMatcher.end();
            int keyStart = tokenMatcher.start(1);
            int keyEnd = tokenMatcher.end(1);

            output.append(text.substring(cursor, tokenStart));

            String token = text.substring(tokenStart, tokenEnd);
            String key = text.substring(keyStart, keyEnd);

            if (valuesByKey.containsKey(key)) {
                String value = valuesByKey.get(key);
                output.append(value);
            } else {
                output.append(token);
            }

            cursor = tokenEnd;
        }
        output.append(text.substring(cursor));

        return output.toString();
    }

}
4
ответ дан 4 December 2019 в 06:30
поделиться
var wordCount =
    from word in words
    group word by word into g
    select new { g.Key, Count = g.Count() };    

Это взято из одного из примеров в linqpad

private static Pattern tokenPattern = Pattern.compile("\\{([^}]*)\\}");

public static String process(String template, Map<String, Object> params) {
    StringBuffer sb = new StringBuffer();
    Matcher myMatcher = tokenPattern.matcher(template);
    while (myMatcher.find()) {
        String field = myMatcher.group(1);
        myMatcher.appendReplacement(sb, "");
        sb.append(doParameter(field, params));
   }
    myMatcher.appendTail(sb);
    return sb.toString();
}

Где doParameter получает значение из карты и преобразует его в строку и выдает исключение, если его нет.

Обратите внимание, что я изменил шаблон, чтобы найти пустые фигурные скобки (например, {}), так как это явным образом проверяется условие ошибки.

EDIT: Обратите внимание, что appendReplacement не зависит от содержимого строки. Согласно javadocs, он распознает $ и обратную косую черту как специальный символ, поэтому я добавил несколько экранирований, чтобы обработать это в примере выше. Это сделано не самым осознанным образом, но в моем случае это не настолько большая проблема, чтобы стоить попытки микрооптимизировать создание строк.

Благодаря комментарию Алана М, это можно сделать еще проще. чтобы избежать проблем со специальными символами при добавлении замены.

Обратите внимание, что я изменил шаблон, чтобы найти пустые фигурные скобки (т. Е. {}), Поскольку это явное условие ошибки.

РЕДАКТИРОВАТЬ: Обратите внимание, что appendReplacement не зависит от содержимого строки. Согласно javadocs, он распознает $ и обратную косую черту как специальный символ, поэтому я добавил несколько экранирований, чтобы обработать это в примере выше. Это сделано не самым осознанным образом, но в моем случае это не настолько большая проблема, чтобы стоить попытки микрооптимизировать создание строк.

Благодаря комментарию Алана М, это можно сделать еще проще. чтобы избежать проблем со специальными символами при добавлении замены.

Обратите внимание, что я изменил шаблон, чтобы найти пустые фигурные скобки (т. Е. {}), Поскольку это явное условие ошибки.

РЕДАКТИРОВАТЬ: Обратите внимание, что appendReplacement не зависит от содержимого строки. Согласно javadocs, он распознает $ и обратную косую черту как специальный символ, поэтому я добавил несколько экранирований, чтобы обработать это в примере выше. Это сделано не самым осознанным образом, но в моем случае это не настолько большая проблема, чтобы стоить попытки микрооптимизировать создание строк.

Благодаря комментарию Алана М это можно сделать еще проще. чтобы избежать проблем со специальными символами при добавлении замены.

он распознает $ и обратную косую черту как специальный символ, поэтому я добавил несколько экранирований, чтобы обработать это в примере выше. Это сделано не самым осознанным образом, но в моем случае это не настолько большая проблема, чтобы стоить попытки микрооптимизировать создание строк.

Благодаря комментарию Алана М, это можно сделать еще проще. чтобы избежать проблем со специальными символами при добавлении замены.

он распознает $ и обратную косую черту как специальный символ, поэтому я добавил несколько экранирований, чтобы обработать это в примере выше. Это сделано не самым осознанным образом, но в моем случае это не настолько большая проблема, чтобы стоить попытки микрооптимизировать создание строк.

Благодаря комментарию Алана М, это можно сделать еще проще. чтобы избежать проблем со специальными символами при добавлении замены.

11
ответ дан 4 December 2019 в 06:30
поделиться
String.replaceAll("{FIRST_NAME}", actualName);

Ознакомьтесь с javadocs для этого здесь .

6
ответ дан 4 December 2019 в 06:30
поделиться

Что ж, я бы предпочел использовать String.format () или лучше MessageFormat .

8
ответ дан 4 December 2019 в 06:30
поделиться

С import java.util.regex. *:

Pattern p = Pattern.compile("{([^{}]*)}");
Matcher m = p.matcher(line);  // line being "Hello, {FIRST_NAME}..."
while (m.find) {
  String key = m.group(1);
  if (map.containsKey(key)) {
    String value= map.get(key);
    m.replaceFirst(value);
  }
}

Итак, регулярное выражение рекомендуется, потому что оно может легко идентифицировать места, требующие замены в строке, а также извлекать имя ключ для подмены. Это намного эффективнее, чем разрыв всей строки.

Вы, вероятно, захотите выполнить цикл со строкой Matcher внутри и строкой Pattern снаружи, чтобы вы могли заменить все строки. Шаблон никогда не нужно перекомпилировать, и более эффективно избежать этого без необходимости.

3
ответ дан 4 December 2019 в 06:30
поделиться

Самым простым может показаться что-то вроде этого:

public static void main(String[] args) {
    String tokenString = "Hello {FIRST_NAME}, this is a personalized message for you.";
    Map<String, String> tokenMap = new HashMap<String, String>();
    tokenMap.put("{FIRST_NAME}", "Jim");
    String transformedString = tokenString;
    for (String token : tokenMap.keySet()) {
        transformedString = transformedString.replace(token, tokenMap.get(token));
    }
    System.out.println("New String: " + transformedString);
}

Он перебирает все ваши токены и заменяет каждый токен тем, что вам нужно, и использует стандартный метод String для замена, тем самым пропуская все разочарования с RegEx.

2
ответ дан 4 December 2019 в 06:30
поделиться

В зависимости от того, насколько до смешного сложна ваша строка, вы можете попробовать использовать более серьезный язык шаблонов строк, например Velocity. В случае Velocity вы бы сделали что-то вроде этого:

Velocity.init();
VelocityContext context = new VelocityContext();
context.put( "name", "Bob" );
StringWriter output = new StringWriter();
Velocity.evaluate( context, output, "", 
      "Hello, #name, this is a personalized message for you.");
System.out.println(output.toString());

Но это, вероятно, излишне, если вы хотите заменить только одно или два значения.

2
ответ дан 4 December 2019 в 06:30
поделиться

Документы означают, что вам следует предпочесть писать токенизатор на основе регулярных выражений, IIRC. Что может подойти вам лучше, так это стандартный поиск-замена регулярного выражения.

0
ответ дан 4 December 2019 в 06:30
поделиться
import java.util.HashMap;

public class ReplaceTest {

  public static void main(String[] args) {
    HashMap<String, String> map = new HashMap<String, String>();

    map.put("FIRST_NAME", "Jim");
    map.put("LAST_NAME",  "Johnson");
    map.put("PHONE",      "410-555-1212");

    String s = "Hello {FIRST_NAME} {LAST_NAME}, this is a personalized message for you.";

    for (String key : map.keySet()) {
      s = s.replaceAll("\\{" + key + "\\}", map.get(key));
    }

    System.out.println(s);
  }

}
1
ответ дан 4 December 2019 в 06:30
поделиться

Обычно в таком случае мы использовали бы MessageFormat вместе с загрузкой фактического текста сообщения из ResourceBundle. Это дает вам дополнительное преимущество - дружелюбие к G10N.

0
ответ дан 4 December 2019 в 06:30
поделиться
Другие вопросы по тегам:

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