《正則表達式經典實例(第2版)》——2.7 Unicode碼位、類別、區塊和字母表
本節書摘來自異步社區《正則表達式經典實例(第2版)》一書中的第2章,第2.7節,作者: 【美】Jan Goyvaerts , Steven Levithan著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看
2.7 Unicode碼位、類別、區塊和字母表
問題描述
使用一個正則表達式來查找商標符號(™),要求通過指定其Unicode碼位,而不是複製並粘貼一個實際上的商標符號。如果你選擇複製並粘貼,那麼商標符號可以被看作另外一個字麵字符,即使並不能從鍵盤上直接輸入它。字麵字符已經在實例2.1中進行了討論。
創建一個正則表達式來匹配Unicode“貨幣符號”(Currency Symbol)類別的任意字符。
創建一個正則表達式來匹配在Unicode“希臘擴展”區塊中的任意字符。
創建一個正則表達式來匹配根據Unicode標準屬於希臘字母表一部分的任意字符。
創建一個正則表達式來匹配一個字形(grapheme),它通常也被當作同一個字符:一個基本字符加上它所有的組合標記。
解決方案
Unicode碼位
\u2122
正則選項:無
正則流派:.NET、Java、JavaScript、Python、Ruby 1.9
\U00002122
正則選項:無
正則流派:Python
在Python 2.x中,這些正則表達式需要作為一個Unicode字符串u"\u2122"或u"\U00002122"引用。
\x{2122}
正則選項:無
正則流派:Java 7、PCRE、Perl
PCRE必須使用UTF-8支持進行編譯,在PHP中,需要使用/u模式修飾符來打開UTF-8支持。
\u{2122}
正則選項:無
正則流派:Ruby 1.9
Ruby 1.8不支持Unicode正則表達式。
Unicode類別
\p{Sc}
正則選項:無
正則流派:.NET、Java、XRegExp、PCRE、Perl、Ruby 1.9
PCRE必須使用UTF-8支持進行編譯,在PHP中,需要使用/u模式修飾符來打開UTF-8支持。JavaScript和Python不支持Unicode屬性。可以使用XRegExp為JavaScript添加Unicode屬性支持。Ruby 1.8不支持Unicode正則表達式。
Unicode 區塊
\p{IsGreekExtended}
正則選項:無
正則流派:.NET、Perl
\p{InGreekExtended}
正則選項:無
正則流派:Java、XRegExp、Perl
JavaScript、PCRE、Python和Ruby 1.9不支持Unicode區塊。但它們支持Unicode碼位,可以用本例“變體”一節演示的方法匹配區塊。XRegExp可以為JavaScript添加Unicode區塊支持。
Unicode字母表
\p{Greek}
正則選項:無
正則流派:XRegExp、PCRE、Perl、Ruby 1.9
\p{IsGreek}
正則選項:無
正則流派:Java 7、Perl
Unicode字母表(script)支持要求PCRE 6.5或者更新版本,而且PCRE必須使用UTF-8支持進行編譯。在PHP中,需要使用/u模式修飾符來打開UTF-8支持。.NET、JavaScript和Python不支持Unicode屬性。XRegExp可以為JavaScript添加Unicode屬性支持。Ruby 1.8不支持Unicode正則表達式。
Unicode字形
\X
正則選項:無
正則流派:PCRE、Perl
PCRE和Perl都包含一個專門的記號來匹配字形PCRE。必須使用UTF-8支持進行編譯;在PHP中,需要使用/u模式修飾符來打開UTF-8支持。
(?>\P{M}\p{M}*)
正則選項:無
正則流派:.NET、Java、Ruby 1.9
(?:\P{M}\p{M}*)
正則選項:無
正則流派:XRegExp
.NET、Java、XRegExp和Ruby 1.9沒有匹配字形的記號。但是它們支持Unicode類別,可以用來模擬匹配字形。
JavaScript(不使用XRegExp時)和Python不支持Unicode字形。Ruby 1.8不支持Unicode正則表達式。
討論
Unicode 碼位
碼位(code point)是Unicode字符數據庫中的一個條目。碼位與字符是不一樣的,當然這還要基於你給“字符”什麼樣的含義。在Unicode中,在屏幕上作為字符出現的符號被稱作是一個字形(grapheme)。
Unicode碼位U+2122表示的是“商標符號”字符。根據所使用的正則流派的不同,你可以使用‹\u2122›、‹\u{2122}›或‹\x{2122}›來匹配這個字符。
‹\u›的語法要求必須使用四位十六進製數字。這意味著你隻能用它來表示U+0000~U+FFFF的Unicode碼位。
‹\u{⋯}›和‹\x{⋯}›語法則允許花括號間出現1~6位十六進製數字,這可以支持從U+000000~U+10FFFF的所有碼位。你可以使用‹\x{E0}›或‹\x{00E0}›來匹配U+00E0。U+100000之後碼位是很少使用的,字體和操作係統也沒有對它們提供很好的支持。
Python的正則表達式引擎不支持Unicode碼位。Python 2.x中字麵Unicode字符串和Python 3.x中字麵文本字符串需要轉義Unicode碼位。\u0000 ~\uFFFF表示U+0000到U+FFFF的Unicode碼位,\U00000000~\U0010FFFF表示全部Unicode碼位。在\U後必須使用8位十六進製數字,無論是否使用了U+10FFFF以後的Unicode碼位。
在Python代碼中使用字麵字符串硬編碼正則表達式時,可以直接使用‹\u2122›和‹\U00002122›。從文件或用戶輸入中讀取正則式時,如果把這些讀取或接收到的Unicode轉義直接傳遞給re.compile()將不會正常工作。在Python 2.x中,可以調用string.decode ('unicode-escape')解碼Unicode轉義。在Python 3.x中,可以調用string.encode('utf-8'). decode('unicode-escape')。
碼位可以在字符類之內和之外進行使用。
Unicode類別
每個Unicode碼位都屬於一個單獨的Unicode類別(category)。一共存在30個由兩個字母代表的Unicode類別,它們被組織為7個單一字母代表的超類。
‹\p{L}› 任意語言的任意字母
‹\p{Ll}› 一個擁有大寫變體的小寫字母
‹\p{Lu}› 一個擁有小寫變體的大寫字母
‹\p{Lt}› 當隻有單詞的第一個字母被大寫時,出現在單詞開頭的字母
‹\p{Lm}› 可以像字母一樣使用的特殊字符
‹\p{Lo}› 不擁有小寫和大寫變體的字母或者表意文字
‹\p{M}› 用於與另外一個字符組合使用的字符(重音符號、變音符號、包圍框等)
‹\p{Mn}› 用於與另外一個字符組合使用,同時不占用額外空間的字符(重音符號、變音符號等)
‹\p{Mc}› 用於與另外一個字符組合使用,但是會占用額外空間的字符(比如在許多東方語言中的元音符號)
‹\p{Me}› 包含另外一個字符的字符(圓圈、方框、鍵帽等)
‹\p{Z}› 任何種類的空白或不可見的分隔符
‹\p{Zs}› 一個不可見但是卻會占用空間的空白字符
‹\p{Zl}› 行分隔符U+2028
‹\p{Zp}› 段分隔符U+2029
‹\p{S}› 數學符號、貨幣符號、裝飾標誌(dingbat)、製表符(box-drawing)等
‹\p{Sm}› 任意數學符號
‹\p{Sc}› 任意貨幣符號
‹\p{Sk}› 組合符號(標記)自己作為一個完整字符
‹\p{So}› 不屬於數學符號、貨幣符號或者組合符號的各種符號
‹\p{N}› 任意字母表中的任意種類的數字字符
‹\p{Nd}› 除了表意字母表之外的任意字母表中的數字0~9
‹\p{Nl}› 看起來像是字母的數字,如羅馬數字
‹\p{No}› 上標或者下標數字,或是非0~9的數字(不包括表意字母表中的數字)
‹\p{P}› 任意種類的標點字符
‹\p{Pd}› 任意種類的連字號或短橫線
‹\p{Ps}› 任意種類的左括號
‹\p{Pe}› 任意種類的右括號
‹\p{Pi}› 任意種類的左引號
‹\p{Pf}› 任意種類的右引號
‹\p{Pc}› 像下劃線一樣用來連接單詞的標點符號
‹\p{Po}› 不屬於短橫線、括號、引號或連接符的任意一種標點字符
‹\p{C}› 不可見的控製字符和未使用的碼位
‹\p{Cc}› ASCII或 Latin-1中0x00~0x1F和0x80~0x9F間字符
‹\p{Cf}› 不可見的格式指示符
‹\p{Co}› 保留私有使用的任意碼位
‹\p{Cs}› 在UTF-16編碼中一個替代對的一半
‹\p{Cn}› 沒有賦予任何字符的碼位
‹\p{Ll}›匹配屬於“小寫字母”類別的單個碼位。‹\p{L}›可以被用作‹[\p{Ll} \p{Lu}\p{Lt}\p{Lm}\p{Lo}]›的簡寫形式,用來匹配在任意“字母”類別中的單個碼位。
‹\P›是‹\p›的否定版本。‹\P{Ll}›匹配不屬於Ll類別的單個碼位。‹\P{L}›匹配不擁有任何“字母”屬性的單個碼位。這與‹[\P{Ll}\P{Lu}\P{Lt}\P{Lm}\P{Lo}]›是不一樣的,後者會匹配所有的碼位。‹\P{Ll}›匹配屬於Lu類別(以及除了Ll之外的所有其他類別)的碼位,而‹\P{Lu}›會包含Ll碼位。把這兩個組合到一個碼位組中就可以把所有可能的碼位都包括進來。
在Perl和PCRE 6.5及以後版本中,‹\p{L&}›可視為‹[\p{Ll}\p{Lu]} \p{Lt}]›的簡寫,匹配字母表中所有擁有大小寫變體的字母。
Unicode區塊
Unicode字符數據庫把所有碼位劃分為不同的區塊。每個區塊由一個連續範圍內的碼位組成。在Unicode 6.1版本的標準中碼位U+0000~U+FFFF被劃分為156個區塊:
‹U+0000…U+007F \p{InBasicLatin}›
‹U+0080…U+00FF \p{InLatin-1Supplement}›
‹U+0100…U+017F \p{InLatinExtended-A}›
‹U+0180…U+024F \p{InLatinExtended-B}›
‹U+0250…U+02AF \p{InIPAExtensions}›
‹U+02B0…U+02FF \p{InSpacingModifierLetters}›
‹U+0300…U+036F \p{InCombiningDiacriticalMarks}›
‹U+0370…U+03FF \p{InGreekandCoptic}›
‹U+0400…U+04FF \p{InCyrillic}›
‹U+0500…U+052F \p{InCyrillicSupplement}›
‹U+0530…U+058F \p{InArmenian}›
‹U+0590…U+05FF \p{InHebrew}›
‹U+0600…U+06FF \p{InArabic}›
‹U+0700…U+074F \p{InSyriac}›
‹U+0750…U+077F \p{InArabicSupplement}›
‹U+0780…U+07BF \p{InThaana}›
‹U+07C0…U+07FF \p{InNKo}›
‹U+0800…U+083F \p{InSamaritan}›
‹U+0840…U+085F \p{InMandaic}›
‹U+08A0…U+08FF \p{InArabicExtended-A}›
‹U+0900…U+097F \p{InDevanagari}›
‹U+0980…U+09FF \p{InBengali}›
‹U+0A00…U+0A7F \p{InGurmukhi}›
‹U+0A80…U+0AFF \p{InGujarati}›
‹U+0B00…U+0B7F \p{InOriya}›
‹U+0B80…U+0BFF \p{InTamil}›
‹U+0C00…U+0C7F \p{InTelugu}›
‹U+0C80…U+0CFF \p{InKannada}›
‹U+0D00…U+0D7F \p{InMalayalam}›
‹U+0D80…U+0DFF \p{InSinhala}›
‹U+0E00…U+0E7F \p{InThai}›
‹U+0E80…U+0EFF \p{InLao}›
‹U+0F00…U+0FFF \p{InTibetan}›
‹U+1000…U+109F \p{InMyanmar}›
‹U+10A0…U+10FF \p{InGeorgian}›
‹U+1100…U+11FF \p{InHangulJamo}›
‹U+1200…U+137F \p{InEthiopic}›
‹U+1380…U+139F \p{InEthiopicSupplement}›
‹U+13A0…U+13FF \p{InCherokee}›
‹U+1400…U+167F \p{InUnifiedCanadianAboriginalSyllabics}›
‹U+1680…U+169F \p{InOgham}›
‹U+16A0…U+16FF \p{InRunic}›
‹U+1700…U+171F \p{InTagalog}›
‹U+1720…U+173F \p{InHanunoo}›
‹U+1740…U+175F \p{InBuhid}›
‹U+1760…U+177F \p{InTagbanwa}›
‹U+1780…U+17FF \p{InKhmer}›
‹U+1800…U+18AF \p{InMongolian}›
‹U+18B0…U+18FF \p{InUnifiedCanadianAboriginalSyllabicsExtended}›
‹U+1900…U+194F \p{InLimbu}›
‹U+1950…U+197F \p{InTaiLe}›
‹U+1980…U+19DF \p{InNewTaiLue}›
‹U+19E0…U+19FF \p{InKhmerSymbols}›
‹U+1A00…U+1A1F \p{InBuginese}›
‹U+1A20…U+1AAF \p{InTaiTham}›
‹U+1B00…U+1B7F \p{InBalinese}›
‹U+1B80…U+1BBF \p{InSundanese}›
‹U+1BC0…U+1BFF \p{InBatak}›
‹U+1C00…U+1C4F \p{InLepcha}›
‹U+1C50…U+1C7F \p{InOlChiki}›
‹U+1CC0…U+1CCF \p{InSundaneseSupplement}›
‹U+1CD0…U+1CFF \p{InVedicExtensions}›
‹U+1D00…U+1D7F \p{InPhoneticExtensions}›
‹U+1D80…U+1DBF \p{InPhoneticExtensionsSupplement}›
‹U+1DC0…U+1DFF \p{InCombiningDiacriticalMarksSupplement}›
‹U+1E00…U+1EFF \p{InLatinExtendedAdditional}›
‹U+1F00…U+1FFF \p{InGreekExtended}›
‹U+2000…U+206F \p{InGeneralPunctuation}›
‹U+2070…U+209F \p{InSuperscriptsandSubscripts}›
‹U+20A0…U+20CF \p{InCurrencySymbols}›
‹U+20D0…U+20FF \p{InCombiningDiacriticalMarksforSymbols}›
‹U+2100…U+214F \p{InLetterlikeSymbols}›
‹U+2150…U+218F \p{InNumberForms}›
‹U+2190…U+21FF \p{InArrows}›
‹U+2200…U+22FF \p{InMathematicalOperators}›
‹U+2300…U+23FF \p{InMiscellaneousTechnical}›
‹U+2400…U+243F \p{InControlPictures}›
‹U+2440…U+245F \p{InOpticalCharacterRecognition}›
‹U+2460…U+24FF \p{InEnclosedAlphanumerics}›
‹U+2500…U+257F \p{InBoxDrawing}›
‹U+2580…U+259F \p{InBlockElements}›
‹U+25A0…U+25FF \p{InGeometricShapes}›
‹U+2600…U+26FF \p{InMiscellaneousSymbols}›
‹U+2700…U+27BF \p{InDingbats}›
‹U+27C0…U+27EF \p{InMiscellaneousMathematicalSymbols-A}›
‹U+27F0…U+27FF \p{InSupplementalArrows-A}›
‹U+2800…U+28FF \p{InBraillePatterns}›
‹U+2900…U+297F \p{InSupplementalArrows-B}›
‹U+2980…U+29FF \p{InMiscellaneousMathematicalSymbols-B}›
‹U+2A00…U+2AFF \p{InSupplementalMathematicalOperators}›
‹U+2B00…U+2BFF \p{InMiscellaneousSymbolsandArrows}›
‹U+2C00…U+2C5F \p{InGlagolitic}›
‹U+2C60…U+2C7F \p{InLatinExtended-C}›
‹U+2C80…U+2CFF \p{InCoptic}›
‹U+2D00…U+2D2F \p{InGeorgianSupplement}›
‹U+2D30…U+2D7F \p{InTifinagh}›
‹U+2D80…U+2DDF \p{InEthiopicExtended}›
‹U+2DE0…U+2DFF \p{InCyrillicExtended-A}›
‹U+2E00…U+2E7F \p{InSupplementalPunctuation}›
‹U+2E80…U+2EFF \p{InCJKRadicalsSupplement}›
‹U+2F00…U+2FDF \p{InKangxiRadicals}›
‹U+2FF0…U+2FFF \p{InIdeographicDescriptionCharacters}›
‹U+3000…U+303F \p{InCJKSymbolsandPunctuation}›
‹U+3040…U+309F \p{InHiragana}›
‹U+30A0…U+30FF \p{InKatakana}›
‹U+3100…U+312F \p{InBopomofo}›
‹U+3130…U+318F \p{InHangulCompatibilityJamo}›
‹U+3190…U+319F \p{InKanbun}›
‹U+31A0…U+31BF \p{InBopomofoExtended}›
‹U+31C0…U+31EF \p{InCJKStrokes}›
‹U+31F0…U+31FF \p{InKatakanaPhoneticExtensions}›
‹U+3200…U+32FF \p{InEnclosedCJKLettersandMonths}›
‹U+3300…U+33FF \p{InCJKCompatibility}›
‹U+3400…U+4DBF \p{InCJKUnifiedIdeographsExtensionA}›
‹U+4DC0…U+4DFF \p{InYijingHexagramSymbols}›
‹U+4E00…U+9FFF \p{InCJKUnifiedIdeographs}›
‹U+A000…U+A48F \p{InYiSyllables}›
‹U+A490…U+A4CF \p{InYiRadicals}›
‹U+A4D0…U+A4FF \p{InLisu}›
‹U+A500…U+A63F \p{InVai}›
‹U+A640…U+A69F \p{InCyrillicExtended-B}›
‹U+A6A0…U+A6FF \p{InBamum}›
‹U+A700…U+A71F \p{InModifierToneLetters}›
‹U+A720…U+A7FF \p{InLatinExtended-D}›
‹U+A800…U+A82F \p{InSylotiNagri}›
‹U+A830…U+A83F \p{InCommonIndicNumberForms}›
‹U+A840…U+A87F \p{InPhags-pa}›
‹U+A880…U+A8DF \p{InSaurashtra}›
‹U+A8E0…U+A8FF \p{InDevanagariExtended}›
‹U+A900…U+A92F \p{InKayahLi}›
‹U+A930…U+A95F \p{InRejang}›
‹U+A960…U+A97F \p{InHangulJamoExtended-A}›
‹U+A980…U+A9DF \p{InJavanese}›
‹U+AA00…U+AA5F \p{InCham}›
‹U+AA60…U+AA7F \p{InMyanmarExtended-A}›
‹U+AA80…U+AADF \p{InTaiViet}›
‹U+AAE0…U+AAFF \p{InMeeteiMayekExtensions}›
‹U+AB00…U+AB2F \p{InEthiopicExtended-A}›
‹U+ABC0…U+ABFF \p{InMeeteiMayek}›
‹U+AC00…U+D7AF \p{InHangulSyllables}›
‹U+D7B0…U+D7FF \p{InHangulJamoExtended-B}›
‹U+D800…U+DB7F \p{InHighSurrogates}›
‹U+DB80…U+DBFF \p{InHighPrivateUseSurrogates}›
‹U+DC00…U+DFFF \p{InLowSurrogates}›
‹U+E000…U+F8FF \p{InPrivateUseArea}›
‹U+F900…U+FAFF \p{InCJKCompatibilityIdeographs}›
‹U+FB00…U+FB4F \p{InAlphabeticPresentationForms}›
‹U+FB50…U+FDFF \p{InArabicPresentationForms-A}›
‹U+FE00…U+FE0F \p{InVariationSelectors}›
‹U+FE10…U+FE1F \p{InVerticalForms}›
‹U+FE20…U+FE2F \p{InCombiningHalfMarks}›
‹U+FE30…U+FE4F \p{InCJKCompatibilityForms}›
‹U+FE50…U+FE6F \p{InSmallFormVariants}›
‹U+FE70…U+FEFF \p{InArabicPresentationForms-B}›
‹U+FF00…U+FFEF \p{InHalfwidthandFullwidthForms}›
‹U+FFF0…U+FFFF \p{InSpecials}›
Unicode區塊是一個連續範圍之內的碼位。雖然許多區塊都擁有Unicode字母表和Unicode類別的名稱,但是它們並不是百分之百相對應的。一個區塊的名稱隻是用來說明它的主要用途。
Currency(貨幣)區塊中並不包含美元和日元符號。由於曆史的原因,這些符號在BasicLatin和Latin-1Supplement區塊中才能找到。但是二者都屬於Currency Symbol(貨幣符號)類別。如果要匹配任何貨幣符號,那麼應該使用\p{Sc},而不是\p{InCurrency}。
大多數區塊中都包含沒有分配的碼位,這些都被包括在了類別‹\p{Cn}›中。其他Unicode類別,以及所有的Unicode字母表中,都不會包含未分配的碼位。
‹\p{InBlockName}›的語法可以在.NET、XRegExp和Perl中使用,而Java使用的則是‹\p{IsBlockName}›的語法。
Perl同樣支持Is變體形式,但是我們推薦你堅持使用In的語法,這是為了不與Unicode字母表發生混淆。對於字母表來說,Perl支持‹\p{Script}›和‹\p{IsScript}›,但是不支持‹\p{InScript}›。
Unicode標準規定區塊名稱不區分大小寫,並且忽略空格、連字符和下劃線。遺憾的是,絕大多數正則流派沒有這麼靈活。.NET所有版本和Java 4都要求符合上表所示大小寫格式。Perl 5.8及以後版本和Java 5及以後版本允許混用大小寫格式。Perl、Java和.NET均支持使用連字符和不含空格的格式。推薦使用這種形式。本書討論的正則流派中,隻有XRegExp和Perl 5.12及以後版本可以靈活處理Unicode區塊名稱中的空格、連字符和下劃線。
Unicode字母表
除了未分配的碼位之外,每個Unicode碼位都是剛好屬於一個Unicode字母表。未分配的碼位不屬於任意字母表。在Unicode 6.1版本的標準中,到U+FFFF之前的已經分配的所有碼位被分配到了如下72個字母表中:
‹\p{Common}› ‹\p{Lepcha}›
‹\p{Arabic}› ‹\p{Limbu}›
‹\p{Armenian}› ‹\p{Lisu}›
‹\p{Balinese}› ‹\p{Malayalam}›
‹\p{Bamum}› ‹\p{Mandaic}›
‹\p{Batak}› ‹\p{Meetei_Mayek}›
‹\p{Bengali}› ‹\p{Mongolian}›
‹\p{Bopomofo}› ‹\p{Myanmar}›
‹\p{Braille}› ‹\p{New_Tai_Lue}›
‹\p{Buginese}› ‹\p{Nko}›
‹\p{Buhid}› ‹\p{Ogham}›
‹\p{Canadian_Aboriginal}› ‹\p{Ol_Chiki}›
‹\p{Cham}› ‹\p{Oriya}›
‹\p{Cherokee}› ‹\p{Phags_Pa}›
‹\p{Coptic}› ‹\p{Rejang}›
‹\p{Cyrillic}› ‹\p{Runic}›
‹\p{Devanagari}› ‹\p{Samaritan}›
‹\p{Ethiopic}› ‹\p{Saurashtra}›
‹\p{Georgian}› ‹\p{Sinhala}›
‹\p{Glagolitic}› ‹\p{Sundanese}›
‹\p{Greek}› ‹\p{Syloti_Nagri}›
‹\p{Gujarati}› ‹\p{Syriac}›
‹\p{Gurmukhi}› ‹\p{Tagalog}›
‹\p{Han}› ‹\p{Tagbanwa}›
‹\p{Hangul}› ‹\p{Tai_Le}›
‹\p{Hanunoo}› ‹\p{Tai_Tham}›
‹\p{Hebrew}› ‹\p{Tai_Viet}›
‹\p{Hiragana}› ‹\p{Tamil}›
‹\p{Inherited}› ‹\p{Telugu}›
‹\p{Javanese}› ‹\p{Thaana}›
‹\p{Kannada}› ‹\p{Thai}›
‹\p{Katakana}› ‹\p{Tibetan}›
‹\p{Kayah_Li}› ‹\p{Tifinagh}›
‹\p{Khmer}› ‹\p{Vai}›
‹\p{Lao}› ‹\p{Yi}›
‹\p{Latin}›
字母表是由某種人類特定語言書寫係統使用的一組碼位組成。一些字母表,如Thai(泰語),對應於單個的人類語言。其他字母表,如Latin(拉丁),則會涉及多種語言。有些語言是由多種字母表來組成的。例如,其中並不存在一種日語Unicode字母表;事實上,Unicode提供了日語文檔中通常會使用到的Hiragana(平假名)、Katakana(片假名)、Han(漢字)和Latin(拉丁)字母表。
在上麵的列表中列在第一個的Common(常見)字母表沒有按照字母順序排列。這種字母表包含了對於許多字母表相同的各種字符,如標點、空白符號以及其他各色符號。
Java要求字母表名稱前使用Is,如‹\p{IsYi}›。Perl允許Is前綴,但不強製要求。XRegExp、PCRE和Ruby則不允許Is前綴。
Unicode標準要求字母表名稱不區分大小寫,並且忽略空格、連字符和下劃線。遺憾的是,絕大多數正則流派沒有這麼靈活。本書中介紹的所有支持字母表的流派都支持符合上表大小寫與下劃線格式的字母表名稱。
Unicode字形
當使用到組合標誌(combining marks)的時候,碼位與字符的區別就展現出來了。Unicode碼位U+0061是“拉丁小寫字母a”,而U+00E0是“加了重音符號的拉丁小寫字母a”。通常來說大多數人把二者都稱作字符。
U+0300是“重音組合符號”的組合標誌。它隻有在一個字母之後使用才有意義。一個包含Unicode碼位U+0061 U+0300的字符串會被顯示為à,這同U+00E0是完全一樣的。組合標誌U+0300會被顯示到字符U+0061的頂上。
之所以會出現兩種不同方式來表示一個加重音符號的字符,是因為在許多曆史上的字符集中,把“帶有重音符號的a”編碼為了單個字符。Unicode的設計者認為有必要與這些常用的遺留字符集保持一對一的映射,另外Unicode新增了把標誌和基本字母分開的表示方式,這樣可以使遺留字符集無法支持的任意組合成為可能。
對於一個正則表達式用戶來說,重要的是本書中介紹的所有正則流派操作的都是碼位而不是圖形化的字符。當我們說正則表達式‹.›匹配單個字符的時候,實際上的含義是它匹配單個的碼位。如果你的目標文本中包含了兩個碼位U+0061 U+0300,在像Java這樣的編程語言中它可以使用字符串常量"\u0061\u0300"來表示,那麼一個點號隻能匹配碼位U+0061(也就是a),而不會匹配重音符號U+0300。使用正則表達式‹..›才可以同時匹配二者。
Perl和PCRE提供了一個特殊的正則表達式記號‹\X›,用來匹配任意單個的Unicode字形。本質上說,它是Unicode版本的特殊點號。無論采取哪種編碼方式,‹\X›都會在文本àà中找到兩個匹配。如果它的編碼是\u00E0\u0061\u0300,那麼第一個匹配是\u00E0,第二個匹配是\u0061\u0300。匹配任何單一Unicode碼位的點號,則會分三次分別匹配\u00E0、\u0061和\u0300。
將Unicode碼位組合視為字形的規則相當複雜1FF。通常來說,要匹配一個字形我們需要匹配不是組合標誌的任意Unicode碼位,以及緊跟其後的所有組合標誌(如果有的話)。我們也可以在支持Unicode的正則流派中使用正則‹(?>\P{M}\p{M})›代替‹\X›記號匹配字形。‹\P{M}›匹配所有不屬於Mark(標誌)類別的符號。‹\p{M}›匹配其後所有的標誌(如果存在的話)。
我們將兩個正則表達式記號放置在同一個固化分組(atomic group)中,確保‹\p{M}*›後麵的正則表達式記號匹配失敗時不會回溯。‹\X{2}.›不會匹配àà,因為在‹\X{2}›匹配兩個重音字母後沒有可供點號匹配的字符。同理‹(?>\P{M}\p{M}*){2}.›也不會匹配àà。但是如果編碼方式為\u00E0\u0061\u0300,則非捕獲型分組‹(?:\P{M} \p{M}*){2}.›可以匹配àà。在第二次嚐試匹配時,‹\p{M}*›會匹配\u0300,而點號則會匹配失敗。因此正則式會回溯,使‹\p{M}*›交回它所匹配的字符,從而使點號成功匹配\u0300。
JavaScript的正則引擎不支持固化分組。XRegExp也無法實現此特性,因為XRegExp仍然依賴JavaScript的正則引擎實現其模式匹配。所以在使用XRegExp時,‹(?>\P{M}\p{M})›是我們最接近的模擬‹\X›的實現。沒有固化分組時,需要牢記正則式中‹(?:\P{M}\p{M})›後麵任何可以匹配標誌(Mark)類別字符的記號都可能使‹\p{M}*›回溯。
變體
否定變體
大寫形式的‹\P›是小寫形式‹\p›的否定變體。例如,‹\P{Sc}›會匹配不擁有“Currency Symbol”(貨幣符號)Unicode屬性的任意字符。所有支持‹\p›的流派都會在其所支持的屬性、區塊和字母表中支持‹\P›。
字符組
所有流派都允許把它們所支持的所有的‹\u›、‹\x›、‹\p›和‹\P›記號用在字符組之內。這樣會把碼位所表示的字符,或者是在該類別、區塊或者字母表中的字符添加到字符組中。例如,你可以用如下的正則式來匹配一個左引號(初始標點屬性)、一個右引號(終止標點屬性)或商標符號(U+2122):
[\p{Pi}\p{Pf}\u2122]
正則選項:無
正則流派:.NET、Java、XRegExp、Ruby 1.9
[\p{Pi}\p{Pf}\x{2122}]
正則選項:無
正則流派:Java 7、PCRE、Perl
列出所有字符
如果你的正則表達式流派不支持Unicode類別、區塊或字母表的話,那麼你可以把屬於該類別、區塊或字母表的字符枚舉到一個字符組中。對於區塊來說,這會比較容易:因為每個區塊其實就是兩個碼位之間的一個範圍。例如,希臘語擴展(Greek Extended)區塊包括U+1F00~U+1FFF的字符:
[\u1F00-\u1FFF]
正則選項:無
正則流派:.NET、Java、JavaScript、Python、Ruby 1.9
[\x{1F00}-\x{1FFF}]
正則選項:無
正則流派:Java 7、PCRE、Perl
然而對於大多數類別和許多字母表來說,與之等價的字符組是單個碼位和較短範圍的一張冗長列表。構成每個類別和許多字母表的字符是散布在Unicode表中的。下麵表示的是希臘語字母表:
[\u0370-\u0373\u0375-\u0377\u037A-\u037D\u0384\u0386\u0388-\u038A↵
\u038C\u038E-\u03A1\u03A3-\u03E1\u03F0-\u03FF\u1D26-\u1D2A\u1D5D-\u1D61↵
\u1D66-\u1D6A\u1DBF\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D↵
\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FC4↵
\u1FC6-\u1FD3\u1FD6-\u1FDB\u1FDD-\u1FEF\u1FF2-\u1FF4\u1FF6-\u1FFE\u2126↵
\U00010140-\U0001018A\U0001D200-\U0001D245]
正則選項:無
正則流派:Python
在構造這個正則表達式的過程中,我們用UnicodeSet Web應用(https://unicode.org/cldr/utility/list-unicodeset.jsp
)生成了希臘語的字母表。在文本框輸入\p{Greek},勾選“Abbreviate”(縮寫)和“Escape”(轉義)複選框,再單擊“Show Set”(顯示碼位集)按鈕。
如本實例先前“Unicode碼位”一節的解釋,隻有Python支持這種Unicode碼位語法。要使其他正則流派使用此正則表達式,需要做一些修改。
如果從字符組中刪除U+FFFF以後的碼位,則很多流派可以正常使用此表達式:
[\u0370-\u0373\u0375-\u0377\u037A-\u037D\u0384\u0386\u0388-\u038A↵
\u038C\u038E-\u03A1\u03A3-\u03E1\u03F0-\u03FF\u1D26-\u1D2A\u1D5D-\u1D61↵
\u1D66-\u1D6A\u1DBF\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D↵
\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FC4↵
\u1FC6-\u1FD3\u1FD6-\u1FDB\u1FDD-\u1FEF\u1FF2-\u1FF4\u1FF6-\u1FFE\u2126]
正則選項:無
正則流派:.NET、Java、JavaScript、Python、Ruby 1.9
對於Unicode碼位,Perl和PCRE使用不同的語法。在上述正則式中,需要把‹\uFFFF›替換為‹\x{FFFF}›、‹\U0010FFFF›替換為‹\x{10FFFF}›。Java 7同樣支持這個正則式:
[\x{0370}-\x{0373}\x{0375}-\x{0377}\x{037A}-\x{037D}\x{0384}\x{0386}↵
\x{0388}-\x{038A}\x{038C}\x{038E}-\x{03A1}\x{03A3}-\x{03E1}↵
\x{03F0}-\x{03FF}\x{1D26}-\x{1D2A}\x{1D5D}-\x{1D61}\x{1D66}-\x{1D6A}↵
\x{1DBF}\x{1F00}-\x{1F15}\x{1F18}-\x{1F1D}\x{1F20}-\x{1F45}↵
\x{1F48}-\x{1F4D}\x{1F50}-\x{1F57}\x{1F59}\x{1F5B}\x{1F5D}\x{1F5F}-↵
\x{1F7D}\x{1F80}-\x{1FB4}\x{1FB6}-\x{1FC4}\x{1FC6}-\x{1FD3}\x{1FD6}-↵
\x{1FDB}\x{1FDD}-\x{1FEF}\x{1FF2}-\x{1FF4}\x{1FF6}-\x{1FFE}\x{2126}↵
\x{10140}-\x{10178}\x{10179}-\x{10189}\x{1018A}\x{1D200}-\x{1D245}]
正則選項:無
正則流派:Java 7、PCRE、Perl
最後更新:2017-06-06 07:35:25