JavaScript >> Javascript 文檔 >  >> Tags >> regex

XRegExp:擴展的 JavaScript 正則表達式構造函數

更新: 此版本的 XRegExp 已過時。請參閱 XRegExp.com 獲取最新、最棒的版本。

我在 JavaScript 中經常使用正則表達式,雖然 exec() 方法很糟糕,而且我喜歡在 replace() 方法中使用函數來生成替換的能力,但 JavaScript 正則表達式缺乏許多其他語言中可用的一些非常重要的特性.我最大的煩惱之一是缺乏對 03 的支持 和 15 標誌,應該分別啟用“點匹配所有”(也稱為單行)模式和“自由間距和註釋”模式。這些修飾符在幾乎所有其他現代正則表達式庫中都可用。

為了解決這個問題,我創建了一個(非常小的)腳本,它擴展了 JavaScript 27 構造函數,啟用上述標誌。基本上,它為您提供了一個名為 34 的構造函數 它的工作原理與 44 完全相同 構造函數,除了它也接受 5169 作為標誌,除了已經支持的 74 (全局),88 (不區分大小寫)和 91 (多行,即 104110 在換行符處匹配)。作為獎勵,123 還提高了跨瀏覽器正則表達式語法的一致性。

以下是它的工作原理:

var regex = new XRegExp("te?", "gi");
var value = "Test".replace(regex, "z"); // value is now "zsz"

看起來熟悉?如果你以前在 JavaScript 中使用過正則表達式,那應該 - 就像使用 131 .但是,到目前為止,我們還沒有做任何使用原生 141 無法完成的事情 構造函數。 156 標誌是不言自明的(具體細節可以在下面的常見問題中找到),所以這裡有一個 164 的例子 標誌:

// Turn email addresses into links
var email = new XRegExp(
    "\\b                                      " +
    "# Capture the address to $1            \n" +
    "(                                        " +
    "  \\w[-.\\w]*               # username \n" +
    "  @                                      " +
    "  [-.a-z0-9]+\\.(?:com|net) # hostname \n" +
    ")                                        " +
    "\\b                                      ", "gix");

value = value.replace(email, "<a href=\"mailto:$1\">$1</a>");

那肯定不一樣!幾個注意事項:

  • 使用 174 時 , 普通的字符串轉義規則(特殊字符前面帶有 "\ ") 是必需的,就像 182 .因此,196 的三個實例 是字符串文字本身中的元序列。 JavaScript 在 205 之前將它們轉換為換行符(結束註釋) 看到字符串。
  • 電子郵件正則表達式過於簡單,僅用於演示目的。

這相當漂亮,但我們可以讓這更容易。如果你運行下面這行代碼:

XRE.overrideNative();

…就像魔法一樣,210 構造函數本身將支持 224239 從那時起的標誌。折衷方案是您將不再能夠訪問有關最後一場比賽的信息作為全局 240 的屬性 目的。但是,無論如何,這些屬性都已正式棄用,您可以通過正則表達式實例上的屬性組合和 259 的使用來訪問所有相同的信息 方法。

這是一個快速常見問題解答。對於前兩個問題,我借用了 O'Reilly 的 Mastering Regular Expressions, 3 rd 的部分解釋 版本 .

s到底是什麼意思 標記做什麼?
通常,點不匹配換行符。但是,點匹配換行符的模式與點不匹配的模式一樣有用。 261 flag 允許在每個正則表達式的基礎上選擇模式。請注意,字符類中的點(例如,272 ) 總是等同於文字點。

至於究竟什麼被認為是換行符(因此除非使用 285 flag),根據 Mozilla 開發人員中心,它包括與以下正則表達式匹配的四個字符:299
x 究竟是什麼 標記做什麼?
首先,它會導致大多數空白被忽略,因此您可以“自由格式化”表達式以提高可讀性。其次,它允許以 # 開頭的評論 .

具體來說,它將大部分空格變成“忽略我”的元字符,而 # 變成“忽略我,以及直到下一個換行符的所有其他內容”元字符。它們不被視為字符類中的元字符(這意味著類不是 自由格式,即使使用 309 ),與其他元字符一樣,您可以轉義空格和 # 你想從字面上理解。當然,你總是可以使用 311 匹配空格,如 323 .請注意,將空格和註釋描述為忽略我的元字符並不十分準確;將它們視為無所事事的元字符可能會更好。這種區別對於像 332 這樣的東西很重要 ,其中與 348 標誌被視為 351 後跟 364 ,而不是 378 .最後,不要緊跟空格或帶有量詞的註釋(例如,382391 ),否則您將量化無所事事的元字符。

至於究竟什麼是空白,根據 Mozilla 開發者中心的說法,它相當於以下正則表達式匹配的所有字符:
<代碼>409
可以sx 標誌可以一起使用嗎?
是的。您可以組合所有支持的標誌 (415 , 426 , 437 , 446 , 457 ) 以任何順序。
XRegExp 支持哪些正則表達式語法?
無論您的瀏覽器本機支持什麼。
您提到了一些關於提高跨瀏覽器正則表達式語法一致性的內容?
使用 464 時 , 一個前導的、未轉義的 473 在字符類中被視為文字字符,因此不會結束該類。這與我使用的其他正則表達式引擎一致,並且在 Internet Explorer 中也是如此。但是,在 Firefox 中可能會遇到以下怪癖(錯誤?):
  • 484 相當於 490 ,儘管它應該會引發錯誤。
  • 503 相當於 513 , 雖然它應該等同於 526536 .
  • 547 相當於 555 (永遠不會匹配),儘管它應該會引發錯誤。
  • 560 相當於 573 (永遠不會匹配),儘管它應該等同於 582599 .
使用 605 時 (或 616 使用 629 ),你不必擔心不同的瀏覽器如何處理這個問題,作為領先的 635 在一個角色類中永遠不會結束這個類。
XRegExp 支持哪些正則表達式相關的方法?
全部。
使用 XRegExp 構建的正則表達式是否比其他方式慢?
沒有。
是否需要更長的時間來構建 使用 XRegExp 的正則表達式比其他方式更好嗎?
是的,少量。從個人測試來看,使用 XRegExp 構建正則表達式通常比其他方式花費的時間不到一毫秒。鑑於不需要在循環中構造正則表達式,這尤其微不足道。相反,應該在進入循環之前將正則表達式分配給變量,以避免在循環的每次迭代期間重新構建它。
在哪些瀏覽器上測試過?
Firefox 2、Internet Explorer 5.5–7 和 Opera 9。
腳本文件有多大?
縮小,小於 1KB。 Gzipping 進一步減少了它。
這是根據什麼許可證發布的?
MIT 許可證。
XRegExp 會影響正則表達式文字嗎?
沒有。即使使用 646 , Perl 風格的正則表達式文字(例如,659 ) 不受影響。
我發現了一個錯誤。你怎麼這麼爛?
你確定 bug 是在 XRegExp 中嗎?正則表達式語法有些複雜,並且經常在給定上下文的情況下改變其含義。此外,JavaScript 字符串文字中的元序列可以在 XRegExp 看到你的正則表達式之前改變事情。無論如何,無論您是否確定您知道是什麼導致了問題,請隨時發表評論,我會盡快調查。

這是腳本,帶有註釋:

/*----------------------------------------------------------------------
XRegExp 0.1, by Steven Levithan <http://stevenlevithan.com>
MIT-style license
------------------------------------------------------------------------
Adds support for the following regular expression features:
  - The "s" flag: Dot matches all (a.k.a, single-line) mode.
  - The "x" flag: Free-spacing and comments mode.

XRegExp also offers consistent, cross-browser handling when "]" is used
as the first character within a character class (e.g., "[]]" or "[^]]").
----------------------------------------------------------------------*/

var XRegExp = function(pattern, flags){
	if(!flags) flags = "";
	
	/* If the "free-spacing and comments" modifier (x) is enabled, replace unescaped whitespace as well as unescaped pound
	signs (#) and any following characters up to and including the next newline character (\n) with "(?:)". Using "(?:)"
	instead of just removing matches altogether prevents, e.g., "\1 0" from becoming "\10" (which has different meanings
	depending on context). None of this applies within character classes, which are unaffected even when they contain
	whitespace or pound signs (which is consistent with pretty much every library except java.util.regex). */
	if(flags.indexOf("x") !== -1){
		pattern = pattern.replace(XRE.re.xMod, function($0, $1, $2){
			// If $2 is an empty string or its first character is "[", return the match unviolated (an effective no-op).
			return (/[^[]/.test($2.charAt(0)) ? $1 + "(?:)" : $0);
		});
	}
	
	/* Two steps (the order is not important):
	
	1. Since a regex literal will be used to return the final regex function/object, replace characters which are not
	   allowed within regex literals (carriage return, line feed) with the metasequences which represent them (\r, \n),
	   accounting for both escaped and unescaped literal characters within pattern. This step is only necessary to support
	   the XRE.overrideNative() method, since otherwise the RegExp constructor could be used to return the final regex.
	
	2. When "]" is the first character within a character class, convert it to "\]", for consistent, cross-browser handling.
	   This is included to workaround the following Firefox quirks (bugs?):
	     - "[^]" is equivalent to "[\S\s]", although it should throw an error.
	     - "[^]]" is equivalent to "[\S\s]]", although it should be equivalent to "[^\]]" or "(?!])[\S\s]".
	     - "[]" is equivalent to "(?!)" (which will never match), although it should throw an error.
	     - "[]]" is equivalent to "(?!)]" (which will never match), although it should be equvialent to "[\]]" or "]".
	   
	   Note that this step is not just an extra feature. It is in fact required in order to maintain correctness without
	   the aid of browser sniffing when constructing the regexes which deal with character classes (XRE.re.chrClass and
	   XRE.re.xMod). They treat a leading "]" within a character class as a non-terminating, literal character. */
	pattern = pattern.replace(XRE.re.badChr, function($0, $1, $2){
			return $1 + $2.replace(/\r/, "\\r").replace(/\n/, "\\n");
		}).
		replace(XRE.re.chrClass, function($0, $1, $2){
			return $1 + $2.replace(/^(\[\^?)]/, "$1\\]");
		});
	
	// If the "dot matches all" modifier (s) is enabled, replace unescaped dots outside of character classes with [\S\s]
	if(flags.indexOf("s") !== -1){
		pattern = pattern.replace(XRE.re.chrClass, function($0, $1, $2){
			return $1.replace(XRE.re.sMod, function($0, $1, $2){
					return $1 + ($2 === "." ? "[\\S\\s]" : "");
				}) + $2;
		});
	}
	
	// Use an evaluated regex literal to return the regular expression, in order to support the XRE.overrideNative() method.
	return eval("/" + pattern + "/" + flags.replace(/[sx]+/g, ""));
},
XRE = {
	overrideNative: function(){
		/* Override the global RegExp constructor/object with the enhanced XRegExp constructor. This precludes accessing
		properties of the last match via the global RegExp object. However, those properties are deprecated as of
		JavaScript 1.5, and the values are available on RegExp instances or via the exec() method. */
		RegExp = XRegExp;
	},
	re: {
		chrClass: /((?:[^[\\]+|\\(?:[\S\s]|$))*)((?:\[\^?]?(?:[^\\\]]+|\\(?:[\S\s]|$))*]?)?)/g,
		xMod: /((?:[^[#\s\\]+|\\(?:[\S\s]|$))*)((?:\[\^?]?(?:[^\\\]]+|\\(?:[\S\s]|$))*]?|\s*#[^\n\r]*[\n\r]?\s*|\s+)?)/g,
		sMod: /((?:[^\\.]+|\\(?:[\S\s]|$))*)(\.?)/g,
		badChr: /((?:[^\\\r\n]+|\\(?:[^\r\n]|$(?!\s)))*)\\?([\r\n]?)/g
	}
};
/* XRE.re is used to cache the more complex regexes so they don't have to be recompiled every time XRegExp runs. Note that
the included regexes match anything (if they didn't, they would have to be rewritten to avoid catastrophic backtracking on
failure). It's the backreferences, as well as where one match ends and the next begins, that's important. Also note that
the regexes are exactly as they are in order to account for all kinds of caveats involved in interpreting and working with
JavaScript regexes. Do not modify them! */

在這裡下載 .

更新: 此版本的 XRegExp 已過時。請參閱 XRegExp.com 獲取最新、最棒的版本。


Tutorial JavaScript 教程
  1. 在 React 中創建簡單的登錄表單

  2. React 和 TypeScript Pt.4 入門 - 入門技巧

  3. 創建 Observables:第二部分

  4. 內容安全策略 - 保護您的網站免受 XSS 攻擊

  5. 需要節點——第 55 卷

  6. 構建自定義 React Hooks

  7. Object(...) 不是 Vuex Store 的函數

  1. D3:未來 10 年的 JS 庫?

  2. 以菜鳥的身份開始 Vanila Js....如果您想在這段旅程中相處融洽。 (第二天)

  3. 在 JavaScript 中使用 FormData API

  4. 2021 年關於以靈活高效的方式構建 Next.js 項目的指南

  5. 一個有趣的 JavaScript 面試挑戰

  6. Monadic 錯誤處理的其他工具

  7. 如何在遷移中更新約束

  1. 合作夥伴更新:Mobilize.Net 宣布支持 Kendo UI 的 WebMAP 5

  2. 跟踪您的 NGRX 操作狀態

  3. Vue 使用狀態效果。我們都知道 Vuex。這是一個很棒的…

  4. 每個遊戲開發者都應該知道的 4 個 3D 渲染引擎