Unless you have further restrictions on your input, your code cannot be correct. You're assuming there can be tag nesting, so you should be making a parser.
As far as I can tell, your grammar is:
text -> text tag_open text tag_close text
text -> char_sequence
tag_open -> '[' identifier ']'
tag_close -> '[/' identifier ']'
Where char_sequence
is some (possibly empty) sequence of characters that don't contain [
and identifier
is some sequence of (probably alphanumeric + underscore) characters.
Now you could use something like PLY to build a syntax tree. You'll have to define your terminals:
char_sequence = r"[^\[]*"
tag_open = r"\[[a-zA-Z0-9_]+\]"
tag_close = r"\[/[a-zA-Z0-9_]+\]"
Now you've got to build your abstract syntax tree. I would advise a class Node
that contains a list of children, the associated tag, and the text in it. Thus, something like
def Node(object):
def __init__(self, tag_name, text):
self.tag_name = tag_name
self.text = text
self.children = []
def add_child(self, child):
self.children.append(child)
You'd want [tag]Hello![tag]Hi![/tag][/tag]
to parse to a Node
that has the tag_name
tag
, the text
Hello!
, and a single child.
Once you have that, you can go ahead and define the grammar rules. PLY lets you do that with
def p_tag_in_text(p):
"""text : text open_tag text close_tag text"""
# You now have an object for each of text, text, open_tag, text, close_tag, text
# and can put them together here.
Once you've defined all parser rules, you get an abstract syntax tree, which you can then traverse finding all relevant nodes and calling replace on the text you want.
As you can see, this method is a lot longer and a good deal more complicated. The token examples I showed don't match the grammar -- you'd probably want to split the [
, [/
and ]
out of the tokens, and make sure that close_tag
and open_tag
just contain the identifiers. I've also not entirely specified how the grammar rules should be implemented: the current setup leads to it being unclear where the text is in relation to the tags. You'd have to refine the system somewhat to make that work (probably making the text a kind of child, and appending it at a suitable time.
Because of this, you should first try to restrict your input. If you can ensure a number of things about tag nesting (especially tags containing themselves) it would allow you to do all of this with a regex, and in that case Winston Ewert's solution is what you should go with.