Алгоритм шаблонов и меток

Сначала быстрое определение:)

  • Шаблон . Строка, которая может содержать заполнители (например, "hello [name]")
  • Заполнитель . Подстрока с квадратными скобками (например, "name" в "hello [name]:).
  • Карта свойств - допустимый объект со строками в качестве значений

Мне нужно написать код, который заменит заполнители (вместе с квадратными скобками) соответствующими значениями в карте свойств.

Пример: для следующей карты свойств:

{
    "name":"world",
    "my":"beautiful",
    "a":"[b]",
    "b":"c",
    "c":"my"
}

Ожидаемые результаты:

  • "привет имя" -> "привет имя"

  • "hello [name]" -> "Привет, мир"

  • "[b]" -> "С"

  • "[a]" -> "c" (потому что [a] -> [b] -> [c])

  • "[[b]]" -> "мой" (потому что [[b]] ​​-> g>; my)

  • "привет [мое] [имя]" -> "Привет, прекрасный мир"

4 голоса | спросил Shlomi Schwartz 24 Jam1000000amTue, 24 Jan 2012 02:09:29 +040012 2012, 02:09:29

3 ответа


0
var map = {
    "name":"world",
    "my":"beautiful",
    "a":"[b]",
    "b":"c",
    "c":"my"
};

var str = "hello [my] [name] [[b]]";

do {
    var strBeforeReplace = str;
    for (var k in map) {
        if (!map.hasOwnProperty(k)) continue;
        var needle = "[" + k + "]";
        str = str.replace(needle, map[k]);
    }
    var strChanged = str !== strBeforeReplace;
} while (strChanged);

document.write(str); //hello beautiful world my
ответил goat 24 Jam1000000amTue, 24 Jan 2012 02:23:03 +040012 2012, 02:23:03
0

Ответ @chris превосходен, я просто хочу предоставить альтернативное решение с использованием регулярных выражений, которое работает «наоборот», т. е. не ищет вхождения «версий-заполнителей» всех элементов в свойствах. map, но путем многократного поиска вхождений самого заполнителя и замены его соответствующим значением из карты свойств. Это имеет два преимущества:

  1. Если карта свойств становится очень большой, это решение должно иметь лучшая производительность (все еще для сравнения).
  2. Заполнитель и способ работы подстановок можно легко изменить, настроив регулярное выражение и функцию подстановки (здесь это может не быть проблемой).

Недостатком является, конечно, то, что код немного сложнее (отчасти из-за того, что в JavaScript отсутствует хороший способ подстановки совпадений регулярных выражений с помощью пользовательских функций, вот что substituteRegExp для):

function substituteRegExp(string, regexp, f) {
    // substitute all matches of regexp in string with the value
    // returned by f given a match and the corresponding group values
    var found;
    var lastIndex = 0;
    var result = "";
    while (found = regexp.exec(string)) {
        var subst = f.apply(this, found);
        result += string.slice(lastIndex, found.index) + subst;
        lastIndex = found.index + found[0].length;
    }
    result += string.slice(lastIndex);
    return result;
}

function templateReplace(string, values) {
    // repeatedly substitute [key] placeholders in string by values[key]
    var placeholder = /\[([a-zA-Z0-9]+)\]/g;
    while (true) {
        var newString = substituteRegExp(string, placeholder, function(match, key) {
            return values[key];
        });
        if (newString == string)
            break;
        string = newString;
    }
    return string;
}

alert(templateReplace("hello [[b]] [my] [name]", {
    "name":"world",
    "my":"beautiful",
    "a":"[b]",
    "b":"c",
    "c":"my"
})); // -> "hello my beautiful world"

Обновление . Я провел небольшое профилирование, чтобы сравнить два решения (jsFiddle по адресу http : //jsfiddle.net/n8Fyv/1/, я также использовал Firebug). Хотя решение @chris быстрее для небольших строк (нет необходимости разбирать регулярное выражение и т. Д.), Это решение работает намного лучше для больших строк (порядка тысяч символов). Я не сравнивал различные размеры карты свойств, но ожидал еще больших различий.

Теоретически это решение имеет время выполнения O ( k n ), где k - глубина вложения заполнителей, а n - длина строки (при условии, что для поиска в словаре /хэше требуется постоянное время), а решением @chris является O ( k n m ) где m - количество элементов в карте свойств. Разумеется, все это относится только к крупным материалам.

ответил Jan Pöschko 24 Jam1000000amTue, 24 Jan 2012 03:03:25 +040012 2012, 03:03:25
0

Если вы знакомы с .NET String.Format, вам следует взглянуть на эта реализация JavaScript . Он также поддерживает форматирование чисел, как и String.Format.

Вот пример того, как его использовать:

var result = String.Format("Hello {my} {name}", map);

Однако для создания рекурсивных шаблонов потребуется некоторая модификация.

ответил Scott Rippey 24 Jam1000000amTue, 24 Jan 2012 04:21:12 +040012 2012, 04:21:12

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132