2014-12-30 3 views
0

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

"{b}This is BOLD{/b}".replace(/\{b\}(.*?)\{\/b\}/gi, "00b3f[ $1 00b3d]"); 

// Returns "00b3f[ This is BOLD 00b3d]" 

Я могу сделать это легко, но это становится сложнее, когда более сложная строка передается функции, например:

"{red} This is RED {red} This also should be red {/red} and this {/red}" 
.replace(/\{red\}(.*?)\{\/red\}/gi, "00b4f[ $1 00b4d]"); 

// Returns: 
// "00b4f[ This is RED {red} This also should be red 00b4d] and this {/red}" 

// Where the output should be: 
// "00b4f[ This is RED 00b4f[ This also should be red 00b4d] and this 00b4d]" 

Я хотел бы решить эту проблему с помощью простого RegExp, но я могу» t найти способ сделать это! Я думаю, что смогу сделать это с помощью цикла while, но это будет слишком грязно. Какие-либо предложения?

+1

Вы не можете решить эту проблему с помощью регулярных выражений, потому что язык вы описываете контекстно-зависимая, но не регулярный - в простых терминах это означает «вам нужна память для его анализа», что вы наблюдали. Я рекомендую простой рекурсивный анализатор спуска. –

+0

Related: http://stackoverflow.com/q/1732348/1026459 –

ответ

2

Regex не может иметь дело с вложенными выражениями (если у вас нет доступа к мощной реализации регулярного выражения, в котором нет javascript), поэтому решение с чистым регулярным выражением не может быть и речи. Но есть еще простой способ сделать это:

  1. заменить все вхождения \{(\w+)\}((?:(?!\{\w+\}).)*)\{\/\1\} (это соответствует {tag}...{/tag} пары, но только если она не содержит другую {tag}) с 00b4f[ $2 00b4d].
  2. повторить, пока не будет больше совпадений.

Чтобы сделать эту динамику, используйте функцию обратного вызова для замены:

var tagPattern = /\{(\w+)\}((?:(?!\{\w+\}).)*)\{\/\1\}/g, 
    tagReplacer = function ($0, $1, $2) { 
     switch ($1) { 
      case "b": return "00b3f[" + $2 + " 00b3d]"; 
      case "red": return "00b4f[" + $2 + " 00b4d]"; 
      default: return $2; 
     } 
    }; 

while (tagPattern.test(sourceString)) { 
    sourceString = sourceString.replace(tagPattern, tagReplacer); 
} 
+1

Очень приятное решение. Вы можете расширить это, отметив замену обратных вызовов, я уверен, что OP им понадобится. – Tomalak

+1

+ 1 Очень круто. Небольшой цикл и обратный вызов сделают это очень динамичным и простым в использовании! –

+0

@Tomalak: Я никогда не использовал JavaScript, поэтому, скорее всего, OP знает больше о замене обратных вызовов, чем я. –