[英]How to realize parsing of own html tags in text
我有任务要实现自己的标签,使文本粗体 ,下划线或删除任何嵌套。 像一个
*bold text* _underlinetext_ -strikethrough-
另外我需要像a一样创建自己的超链接
[link | http://stackoverflow.com]
第一个想法来了 - 它适用于正则表达式。 代码:
View.prototype.parseText = function(text) {
text = text.replace(/\*([^\*]+)\*/g, '<b>$1</b>');
text = text.replace(/\_([^\_]+)\_/g, '<u>$1</u>');
text = text.replace(/\-([^\-]+)\-/g, '<s>$1</s>');
text = text.replace(/\[([^\|].+)\|(.+)\]/g, '<a href="$2">$1</a>');
return text;};
它工作但我需要可扩展性。 正则表达式不是一个好主意,因为它是硬编码的。 如何使用有限状态机(或任何jQuery插件)实现该任务? 我将不胜感激任何帮助。
无论你做什么,为了扩展你的标记系统,你需要:1。定义标记,然后2.用等效的HTML替换它。
即使您在js中编写自己的解析器,在一天结束时,您仍然必须执行上述2个步骤,因此它不再具有您现在所拥有的可扩展性。
正则表达式是工作的工具,除非你有其他要求(即只在这样的元素中替换,但在另一个元素中做其他事情,这需要解析)。
您可以在函数中包装正则表达式调用,并在需要扩展该功能时简单地将正则表达式替换添加到该函数。 如果需要多个页面,请将其添加到外部js文件中。
function formatUserContent(text)
{
text = text.replace(/\*([^\*]+)\*/g, '<b>$1</b>');
text = text.replace(/\_([^\_]+)\_/g, '<u>$1</u>');
text = text.replace(/\-([^\-]+)\-/g, '<s>$1</s>');
text = text.replace(/\[([^\|].+)\|(.+)\]/g, '<a href="$2">$1</a>');
return text;
}
完成后,扩展功能就像添加一样简单
text = text.replace(/\+([^\-]+)\+/g, '<em>$1</em>');
在功能的主体。 我怀疑推出自己的有限状态机将更容易扩展,恰恰相反。
在有限的状态机上花费数小时,希望它可能在未来的某个未知时间节省几分钟,这不是一个好的投资......除非你当然想借口写一个有限状态机,在这种情况下, 前进。
作为旁注,我建议让你的正则表达式更加简单。
text = text.replace(/\[([^\|].+)\|\s*(http://.+)\]/g, '<a href="$2">$1</a>');
(除非你有UI元素可以为用户完成工作)
我可以建议你以下实现http://jsfiddle.net/NwRCm/5/
它使用State设计模式(由于JavaScript和目的很少修改)。 在表面下,所有状态都使用正则表达式实现,但在我看来,这是最有效的方式。
/* View definition */
function View(container) {
this.container = container;
this._parsers = [];
this._currentState = 0;
};
View.prototype.parse = function(text) {
var self = this;
this._parsers.forEach(function (e) {
self._parse(e);
});
return this.container.innerHTML;
};
View.prototype._parse = function (parser) {
var text = parser.parse(this.container.innerHTML);
this.container.innerHTML = text;
return text;
};
View.prototype.nextState = function () {
if (this._currentState < this._parsers.length) {
return this._parse(this._parsers[this._currentState++]);
}
return null;
};
View.prototype.addParser = function (parser) {
if (parser instanceof Parser) {
return this._parsers.push(parser);
} else {
throw 'The parser you\'re trying to add is not an instance of Parser';
}
};
/* end of the View definition */
/* Simulation of interface */
function Parser() {};
Parser.prototype.parse = function () {
throw 'Not implemented!';
};
/* Implementation of bold parser */
function BoldParser() {};
BoldParser.prototype = new Parser();
BoldParser.prototype.parse = function (text) {
text = text.replace(/\*([^\*]+)\*/g, '<b>$1</b>');
return text;
};
/* Implementation of underline parser */
function UnderlineParser() {};
UnderlineParser.prototype = new Parser();
UnderlineParser.prototype.parse = function (text) {
text = text.replace(/\_([^\_]+)\_/g, '<u>$1</u>');
return text;
};
/* Link parser */
function LinkParser() {};
LinkParser.prototype = new Parser();
LinkParser.prototype.parse = function (text) {
text = text.replace(/\[([^\|].+)\|(.+)\]/g, '<a href="$2">$1</a>');
return text;
};
var v = new View(document.getElementById('container'));
v.addParser(new UnderlineParser());
v.addParser(new BoldParser());
v.addParser(new LinkParser());
v.nextState();
v.nextState();
v.nextState();
让我更深入地了解一下实施情况。 首先我们有一个基础“类”(构造函数)视图。 每个视图都有它的基本container
和解析器列表,它还记得下一个应该应用哪个解析器。
之后我们有了“抽象类”(构造函数与原型中的方法抛出异常),名为Parser
它定义了一个必须由每个解析器实现的方法parse
。
之后我们只定义不同的具体解析器并将它们添加到视图中。 我们可以逐个传递状态( View
的nextState
)或在单个方法调用中传递所有状态( View
的parse
)。 我们可以动态添加新的解析器。
可以批准的东西包括用于管理解析器的flyweight工厂。
在实现像Template方法这样的不同模式时,使用“抽象”构造函数的方法也非常有用。
也许您想使用现有的库,例如http://www.showdown.im/上的Markdown库
如果您更喜欢自己编写,那么我建议您查看源代码以了解它是如何解析的(也许是Markdown处理器在其他语言中的源代码)。 一些建议:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.