2012-12-22 71 views
4

我有任務實現自己的標籤,使文本大膽,下劃線或刪除任何嵌套。 像如何實現在文本中解析自己的html標籤

*bold text* _underlinetext_ -strikethrough- 

而且我需要讓自己的超級鏈接一樣,來到一個

[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插件)來實現該任務)?我會很感激任何幫助。

+2

任何類型的解析將涉及硬編碼。除非你試圖建立一個能夠動態確定應該被解析成HTML的系統嗎?這會變得非常迅速。 – Corbin

+0

其實,它是。 – milgoff

+0

嘗試查看現有解析器以瞭解其工作原理。 –

回答

3

我可以建議你將以下實現http://jsfiddle.net/NwRCm/5/

它使用狀態設計模式(小,因爲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,它必須由每個解析器實現。

之後,我們只需定義不同的具體解析器並將它們添加到視圖。我們可以逐個傳遞狀態(ViewnextState),或通過一個方法調用(Viewparse)傳遞所有狀態。我們可以動態添加新的解析器。

一個可以批准的東西包括flyweight工廠來管理解析器。

實現不同模式(如Template方法)時,使用「抽象」構造函數的方法也非常有用。

  • 編輯可能會有一些開銷,因爲所有這些構造函數和對象的定義。一切都可以通過回調完成,即每個狀態都是不同的功能。我使用這種方法是因爲我一直在尋找最容易理解的語言,從語言特定的特徵中明確答案。我希望我能實現它。
+0

它看起來非常整潔,但這種85行解析器的效率,可維護性和易於理解的方式要比簡單的7行函數在一個地方收集所有正則表達式操作的效果更好。在一天結束時,這項工作實際上是由相同的正則表達式替換操作完成的,只是需要更多時間來了解它的工作原理,並且每次添加一個「狀態」而不是添加一行時,都需要添加4.這裏有什麼好處? – Sylverdrag

+0

它給你的國家模式的靈活性。它不會給你另一種解析文本的方式,而是獨立的狀態。當你擴展你的功能並且你的狀態封裝了一些額外的數據時,它可以變得更加可維護。它也更可重用。當然,在一天結束時,可以在單行文件中使用10000行代碼或在10個文件內完成工作,每個文件都有100行代碼和分離的關注點。 –

+0

仍然讓我感到極度的矯枉過正。在像你這樣的解決方案變得更易維護並且證明最初的開銷/複雜性之前,你必須將你的功能擴展到完全成熟的標記語言。在目前的情況下,擴展這麼多將是荒謬的,因爲它只會複製HTML的功能,並且只要這個小小的格式化方案達到某種嚴重的複雜程度,它就會變得更加高效和用戶友好,從而允許HTML和禁用特定標籤。 – Sylverdrag

1

也許你想在http://www.showdown.im/

如果你喜歡寫自己,那麼我建議你查看源代碼,看看它是如何解析的(也許是使用現有的庫,例如降價庫其他語言的Markdown處理器的源代碼)。一些給你的建議:

  • 使用jQuery操縱標記
  • 不要使用正則表達式解析語言。當標記元素 混合在一起時,您會遇到問題。
+0

我正要開始使用嵌套標籤的正則表達式,但是意識到使用這種標記,你不會期望同一個標籤被嵌套。你可以通過正則表達式得到什麼樣的問題? – bdares

+0

您可能不希望標記嵌套,但用戶仍可能使用嵌套標記。此外,使用正則表達式,您必須小心「_foo_ _bar_」未標記爲「 foo_ _bar」。 – Rob

+0

他不需要解析HTML標記或任何其他「語言」,他需要用特定標記替換他自己的自定義標記(明確定義)。正則表達式適用於此任務。 – Sylverdrag

3

不管你做什麼,以延長您的標籤系統,你將需要: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元素,會爲用戶做的工作)

+0

'https'怎麼樣? –

+0

如果網站可以通過https訪問,只需使用「https ?:」即可。 – Sylverdrag