[cpif] r425 - branches/alvaro/frontend-web
svn at argo.es
svn at argo.es
Thu Oct 25 01:09:46 CEST 2007
Author: alvaro
Date: Thu Oct 25 01:09:45 2007
New Revision: 425
Log:
Primeros pasos...
Modified:
branches/alvaro/frontend-web/parser_bbcode.py
Modified: branches/alvaro/frontend-web/parser_bbcode.py
==============================================================================
--- branches/alvaro/frontend-web/parser_bbcode.py (original)
+++ branches/alvaro/frontend-web/parser_bbcode.py Thu Oct 25 01:09:45 2007
@@ -1,6 +1,10 @@
# $Id$
-"""BBCode to HTML parser"""
+# TODO: Argumentos en los quotes y en los urls
+# TODO: Url selfargumentada
+# TODO: Integrar unittest
+
+import re
# Allow BBCode syntax errors?
allow_errors = False
@@ -19,256 +23,159 @@
"img": ('<img src="%(arg)s" />', None, True, None)
}
-def escape(text):
- """Escape the conflictive characters into its entities. Please note that
-he "&" character must be traslated into "&" in the URLS, as said
-in http://www.htmlhelp.com/tools/validator/problems.html#amp"""
-
- entities = {
- '"': '"',
- "'": "'"
- }
-# Si hay que hacer otras sustituciones este codigo puede ser util
-# import re
-# pat = "(%s)" % "|".join( map(re.escape, entities.keys()) )
-# return re.sub( pat, lambda m:entities[m.group()], text )
- import xml.sax.saxutils
- return xml.sax.saxutils.escape(text, entities)
-
-
-class BBCodeParser:
- """A BBCode to HTML parser"""
-
- _open = "["
- _close = "]"
- _regexp_start = "\%s.*?\%s" % (_open, _close)
- _regexp_end = "\%s(.*?)\%s" % (_open, _close)
-
- def __init__(self, context = None):
- self._context = context
- self._status = ""
- self._text = ""
- self._tokens = []
- self._tags = []
- self._parsed = []
- def _reset(self):
- """Resets the internal arrays."""
- self._status = ""
- self._tokens = []
- self._tags = []
- self._parsed = []
-
- def feed(self, text):
- """Sets the text to parse"""
- self._text = text
- self._reset()
- self._tokenize()
- self._status = self._parse()
-
- def get_text(self):
- return self._status, "".join([text for text, dummy in self._parsed])
-
- def get_tokens(self):
- return self._status, self._parsed
-
- def _tokenize(self):
- """Tokenize the string and the tags in two separates lists
- Should be called after before _parse."""
- import re
- self._tokens = re.split(self._regexp_start, self._text)
- self._tags = re.findall(self._regexp_end, self._text)
-
- def _close_tag_to_html(self, tag):
- """Translate the BBCode tag to HTML anc close it."""
- return allowed_tags[tag][1] or ""
-
- def _tag_to_html(self, tag):
- """Translates the BBCode tag to HTML"""
- aux = allowed_tags[tag[0]]
- if not tag[1]:
- aux = allowed_tags.get(tag[0] + "*", aux) # Permitimos tag* que no lleva argumentos y puede ser distinto
- if tag[1]:
- tag[1] = tag[1].strip('"')
- tag[1] = tag[1].strip("'")
- return aux[0] % {"arg": escape(tag[1]) if tag[1] else '' }
-
- def _tag_closes(self, tag):
- """Returns true if the tags needs to be closed"""
- if tag[0].startswith("/"):
- return allowed_tags[tag[0][1:]][1]
- return allowed_tags[tag[0]][1]
-
- def _tag_needs_args(self, tag):
- """Returns true if the tag needs arguments"""
- if allowed_tags.get(tag + "*", False):
- return False
- return allowed_tags[tag][2]
-
- def _parse(self):
- """Do the parsing.
- Should be called after _reset, and _tokenize."""
- def get_context():
- return allowed_tags.get(stack[-1], None)[3] if stack else self._context
- def check_context(tag):
- if allowed_tags[tag][3] == self._context and self._context:
- return False
- else:
- return True
- stack = []
- self._parsed.append((True, self._tokens.pop(0), get_context()))
- while self._tags:
- tag = self._tags.pop(0)
- tag = tag.split("=", 1)
- tag[0] = tag[0].strip()
- if tag[0].startswith("/") and tag[0][1:] in allowed_tags.keys() and stack:
- if tag[0][1:] == stack[-1]:
- self._parsed.append((False, self._close_tag_to_html(stack[-1]), get_context()))
- stack.pop(-1)
- elif not allow_errors:
- return "Error, tratando de cerrar %s%s%s no abierto antes" % (self._open, tag[0], self._close)
- else: # Si alguien activa allow_errors mereceria la mas lenta y dolorosa muerte
- # Esto es una chapuza para usuarios estupidos y chapuceros (y ni se si funciona)
- self._parsed.append((False, "%s%s%s" % (self._open, tag[0], self._close), tag[0]))
- if self._tokens and self._tag_closes(tag):
- self._parsed.append((True, self._tokens.pop(0), get_context()))
-
- elif tag[0] in allowed_tags.keys():
- if not check_context(tag[0]):
- return "Error, anidado no valido"
- tag.append(None)
- stack.append(tag[0])
- if self._tag_needs_args(tag[0]) and tag[1] == None:
- tag[1] = self._tokens[0]
- if not allow_errors and not tag[1]:
- return "Error, no se ha pasado el argumento a %s%s%s" % (self._open, tag[0], self._close)
- self._parsed.append((False, self._tag_to_html(tag), get_context()))
- if not self._tag_closes(tag) and self._tokens:
- self._tokens.pop(0)
- if self._tokens:
- self._parsed.append((True, self._tokens.pop(0), get_context()))
-
- else: # Si no conozco el tag se lo paso tal cual
- self._parsed.append((True, "%s%s%s" % (self._open, tag[0], self._close), get_context()))
- if self._tokens:
- self._parsed.append((True, self._tokens.pop(0), get_context()))
-
- if stack and allow_errors:
- while stack: # No me responsabilizo de lo que salga aqui...
- self._parsed.append((False, self._close_tag_to_html(stack[-1]), close_tag))
- stack.pop(-1)
- elif stack:
- return "Error, falta cerrar el tag %s%s%s" % (self._open, stack[-1], self._close)
- return False
-
-def parse(text, context = None):
- """Parses the text into BBCode. It returns the exit code and a list of tuples
-in the form [(Boolean,"text")]. The first element tells whether "text" was
-untouched or analysed."""
- parser = BBCodeParser(context = context)
- parser.feed(text)
- return parser.get_tokens()
-
-import unittest
-class TestBBCode(unittest.TestCase):
- """Test Case for the BBCode parser"""
- correct_bbcode = (
- ('[ b]hola[/b]', '<strong>hola</strong>'),
- ('[b ]hola[/b]', '<strong>hola</strong>'),
- ('[ b ]hola[/b]', '<strong>hola</strong>'),
-
- ('[b]hola[ /b]', '<strong>hola</strong>'),
- ('[b]hola[/b ]', '<strong>hola</strong>'),
- ('[b]hola[ /b ]', '<strong>hola</strong>'),
-
-
- ('[b]hola[/b]', '<strong>hola</strong>'),
- ('antes [b]hola[/b]', 'antes <strong>hola</strong>'),
- ('[b]hola[/b] despues', '<strong>hola</strong> despues'),
- ('antes [b]hola[/b] despues', 'antes <strong>hola</strong> despues'),
-
- ('[url]la direccion[/url]', '<a href="la direccion">la direccion</a>'),
- ('antes [url]la direccion[/url]', 'antes <a href="la direccion">la direccion</a>'),
- ('[url]la direccion[/url] despues', '<a href="la direccion">la direccion</a> despues'),
- ('antes [url]la direccion[/url] despues', 'antes <a href="la direccion">la direccion</a> despues'),
-
- ('[url="la direccion"]el texto[/url]', '<a href="la direccion">el texto</a>'),
- ('antes [url="la direccion"]el texto[/url]', 'antes <a href="la direccion">el texto</a>'),
- ('[url="la direccion"]el texto[/url] despues', '<a href="la direccion">el texto</a> despues'),
- ('antes [url="la direccion"]el texto[/url] despues', 'antes <a href="la direccion">el texto</a> despues'),
-
- ('[url="la direccion"]el texto[/url]', '<a href="la direccion">el texto</a>'),
-
- ('[url="http://example.org/uno&dos"]el texto[/url]', '<a href="http://example.org/uno&dos">el texto</a>'),
-
- ('[url=la direccion]el texto[/url]', '<a href="la direccion">el texto</a>'),
- ('antes [url=la direccion]el texto[/url]', 'antes <a href="la direccion">el texto</a>'),
- ('[url =la direccion]el texto[/url] despues', '<a href="la direccion">el texto</a> despues'),
- ('antes [url=la direccion]el texto[/url] despues', 'antes <a href="la direccion">el texto</a> despues'),
-
- ('[quote=paco]Hola[/quote]', '<blockquote><h4>paco escribió:</h4>Hola</blockquote>'),
- ('antes [quote=paco]Hola[/quote]', 'antes <blockquote><h4>paco escribió:</h4>Hola</blockquote>'),
- ('[quote=paco]Hola[/quote] despues', '<blockquote><h4>paco escribió:</h4>Hola</blockquote> despues'),
- ('antes [quote=paco]Hola[/quote] despues', 'antes <blockquote><h4>paco escribió:</h4>Hola</blockquote> despues'),
-
- ('[quote]Hola[/quote]', '<blockquote>Hola</blockquote>'),
- ('antes [quote]Hola[/quote]', 'antes <blockquote>Hola</blockquote>'),
- ('[quote]Hola[/quote] despues', '<blockquote>Hola</blockquote> despues'),
- ('antes [quote]Hola[/quote] despues', 'antes <blockquote>Hola</blockquote> despues'),
-
- ('[u]hola[/u]', '<span style="text-decoration:underline">hola</span>'),
-
- ('[size=20px]hola[/size]', '<span style="font-size:20px">hola</span>'),
-
- ('[n]hola[/n]', '[n]hola[/n]'),
-
- ("[img]laimagen1[/img]", '<img src="laimagen1" />'),
- ("antes [img]laimagen2[/img]", 'antes <img src="laimagen2" />'),
- ("[img]laimagen3[/img] despues", '<img src="laimagen3" /> despues'),
- ("antes [img]laimagen4[/img] despues", 'antes <img src="laimagen4" /> despues')
- )
-
- incorrect_bbcode = (
- '[i]bla bla bla [b]hola[/n][/i]',
- '[b]Ay[/ b ]',
- '[b]Ay[ / b ]',
- '[b]Ay[/]',
- '[b]Ay, se me ha olvidado cerrar',
- '[url][/url]',
- '[b][/url]hola[/url]',
- '[b]foo[url]hola[/b][/url]',
- """Un texto [b]mas[/b] largo, con [b]negritas y [n]cursivas[/i]
- [/b] e incluso [url="laurl"]enlaces [/b]con negritas[/b] dentro[/url]""")
-
- xss = (
- """[url="hola'"]adios[/url]""",
- """[url="hola''"'"'"]adios[/url]""",
-)
-
-
- def testCorrectBBCode(self):
- """Test if the translation goes well."""
- bbcode_list = []
- html_list = []
- global allow_errors
- allow_errors = False
- for bbcode, html in self.correct_bbcode:
- bbcode_list.append(bbcode)
- html_list.append(html)
- retval, result = parse(bbcode)
- assert not retval
- self.assertEqual(html, "".join(text for dummy, text, dummy in result))
- retval, result = parse("".join(bbcode_list))
- assert not retval
- self.assertEqual("".join(html_list), "".join(text for dummy, text, dummy in result))
-
- def testIncorrectBBCode(self):
- """Test if the translation fails using bad formed BBCode."""
- global allow_errors
- allow_errors = False
- for bbcode in self.incorrect_bbcode:
- retval, result = parse(bbcode)
- assert retval
+tags = {
+ 'b': ['b','b'],
+ 'size': ['size', 'size'],
+ 'quote': ['quote(?:="([^"]+)")?','quote'],
+ 'url': ['url', 'url'],
+ 'img': ['img', None],
+ }
-if __name__ == "__main__":
- unittest.main()
+regexp_tag = re.compile("(\[.*?\])")
+
+for key, value in tags.iteritems():
+ tags[key] = [ re.compile("\[%s\]" % value[0]), re.compile("\[/%s\]"% value[1]) if value[1] else None ]
+
+def escape(text):
+ entities = {
+ '"': '"',
+ "'": "'"
+ }
+ # Si hay que hacer otras sustituciones este codigo puede ser util
+# import re
+# pat = "(%s)" % "|".join( map(re.escape, entities.keys()) )
+# return re.sub( pat, lambda m:entities[m.group()], text )
+ import xml.sax.saxutils
+ return xml.sax.saxutils.escape(text, entities)
+
+
+def parse(text):
+ print "Parseo--->\n %s" % text
+ before = []
+ control = True
+ while control:
+ ret = regexp_tag.split(text,1)
+ before.append(ret[0])
+ tag = ret[1]
+ after = ret[2]
+ for key,value in tags.iteritems():
+ if value[0].match(tag):
+ tag = ('BBCODE',True,tag,None,False)
+ control = False
+ break
+ elif value[1] and value[1].match(tag):
+ tag = ('BBCODE',False,tag,None,False)
+ control = False
+ break
+ if control:
+ before.append(tag)
+ text = after
+ print "".join(before), tag, after
+ return "".join(before), tag, after
+
+#import unittest
+#class TestBBCode(unittest.TestCase):
+# """Test Case for the BBCode parser"""
+# correct_bbcode = (
+# ('[ b]hola[/b]', '<strong>hola</strong>'),
+# ('[b ]hola[/b]', '<strong>hola</strong>'),
+# ('[ b ]hola[/b]', '<strong>hola</strong>'),
+#
+# ('[b]hola[ /b]', '<strong>hola</strong>'),
+# ('[b]hola[/b ]', '<strong>hola</strong>'),
+# ('[b]hola[ /b ]', '<strong>hola</strong>'),
+#
+#
+# ('[b]hola[/b]', '<strong>hola</strong>'),
+# ('antes [b]hola[/b]', 'antes <strong>hola</strong>'),
+# ('[b]hola[/b] despues', '<strong>hola</strong> despues'),
+# ('antes [b]hola[/b] despues', 'antes <strong>hola</strong> despues'),
+#
+# ('[url]la direccion[/url]', '<a href="la direccion">la direccion</a>'),
+# ('antes [url]la direccion[/url]', 'antes <a href="la direccion">la direccion</a>'),
+# ('[url]la direccion[/url] despues', '<a href="la direccion">la direccion</a> despues'),
+# ('antes [url]la direccion[/url] despues', 'antes <a href="la direccion">la direccion</a> despues'),
+#
+# ('[url="la direccion"]el texto[/url]', '<a href="la direccion">el texto</a>'),
+# ('antes [url="la direccion"]el texto[/url]', 'antes <a href="la direccion">el texto</a>'),
+# ('[url="la direccion"]el texto[/url] despues', '<a href="la direccion">el texto</a> despues'),
+# ('antes [url="la direccion"]el texto[/url] despues', 'antes <a href="la direccion">el texto</a> despues'),
+#
+# ('[url="la direccion"]el texto[/url]', '<a href="la direccion">el texto</a>'),
+#
+# ('[url="http://example.org/uno&dos"]el texto[/url]', '<a href="http://example.org/uno&dos">el texto</a>'),
+#
+# ('[url=la direccion]el texto[/url]', '<a href="la direccion">el texto</a>'),
+# ('antes [url=la direccion]el texto[/url]', 'antes <a href="la direccion">el texto</a>'),
+# ('[url =la direccion]el texto[/url] despues', '<a href="la direccion">el texto</a> despues'),
+# ('antes [url=la direccion]el texto[/url] despues', 'antes <a href="la direccion">el texto</a> despues'),
+#
+# ('[quote=paco]Hola[/quote]', '<blockquote><h4>paco escribió:</h4>Hola</blockquote>'),
+# ('antes [quote=paco]Hola[/quote]', 'antes <blockquote><h4>paco escribió:</h4>Hola</blockquote>'),
+# ('[quote=paco]Hola[/quote] despues', '<blockquote><h4>paco escribió:</h4>Hola</blockquote> despues'),
+# ('antes [quote=paco]Hola[/quote] despues', 'antes <blockquote><h4>paco escribió:</h4>Hola</blockquote> despues'),
+#
+# ('[quote]Hola[/quote]', '<blockquote>Hola</blockquote>'),
+# ('antes [quote]Hola[/quote]', 'antes <blockquote>Hola</blockquote>'),
+# ('[quote]Hola[/quote] despues', '<blockquote>Hola</blockquote> despues'),
+# ('antes [quote]Hola[/quote] despues', 'antes <blockquote>Hola</blockquote> despues'),
+#
+# ('[u]hola[/u]', '<span style="text-decoration:underline">hola</span>'),
+#
+# ('[size=20px]hola[/size]', '<span style="font-size:20px">hola</span>'),
+#
+# ('[n]hola[/n]', '[n]hola[/n]'),
+#
+# ("[img]laimagen1[/img]", '<img src="laimagen1" />'),
+# ("antes [img]laimagen2[/img]", 'antes <img src="laimagen2" />'),
+# ("[img]laimagen3[/img] despues", '<img src="laimagen3" /> despues'),
+# ("antes [img]laimagen4[/img] despues", 'antes <img src="laimagen4" /> despues')
+# )
+#
+# incorrect_bbcode = (
+# '[i]bla bla bla [b]hola[/n][/i]',
+# '[b]Ay[/ b ]',
+# '[b]Ay[ / b ]',
+# '[b]Ay[/]',
+# '[b]Ay, se me ha olvidado cerrar',
+# '[url][/url]',
+# '[b][/url]hola[/url]',
+# '[b]foo[url]hola[/b][/url]',
+# """Un texto [b]mas[/b] largo, con [b]negritas y [n]cursivas[/i]
+# [/b] e incluso [url="laurl"]enlaces [/b]con negritas[/b] dentro[/url]""")
+#
+# xss = (
+# """[url="hola'"]adios[/url]""",
+# """[url="hola''"'"'"]adios[/url]""",
+#)
+#
+#
+# def testCorrectBBCode(self):
+# """Test if the translation goes well."""
+# bbcode_list = []
+# html_list = []
+# global allow_errors
+# allow_errors = False
+# for bbcode, html in self.correct_bbcode:
+# bbcode_list.append(bbcode)
+# html_list.append(html)
+# retval, result = parse(bbcode)
+# assert not retval
+# self.assertEqual(html, "".join(text for dummy, text, dummy in result))
+# retval, result = parse("".join(bbcode_list))
+# assert not retval
+# self.assertEqual("".join(html_list), "".join(text for dummy, text, dummy in result))
+#
+# def testIncorrectBBCode(self):
+# """Test if the translation fails using bad formed BBCode."""
+# global allow_errors
+# allow_errors = False
+# for bbcode in self.incorrect_bbcode:
+# retval, result = parse(bbcode)
+# assert retval
+#
+if __name__ == "__main__":
+ parse("caca [f] adf [b] asgsdag [/b]")
+# unittest.main()
+#
More information about the cpif
mailing list