Почему я не могу использовать акцентированные символы рядом с границей слова? - PullRequest
9 голосов
/ 15 марта 2010

Я пытаюсь создать динамическое регулярное выражение, соответствующее имени человека. Он работает без проблем на большинстве имен, пока я не наткнулся на символы с акцентом в конце имени.

Пример: Some Fancy Namé

Регулярное выражение, которое я использовал до сих пор:

/\b(Fancy Namé|Namé)\b/i

Используется так:

"Goal: Some Fancy Namé. Awesome.".replace(/\b(Fancy Namé|Namé)\b/i, '<a href="#">$1</a>');

Это просто не будет совпадать. Если я заменю é на e, это будет просто замечательно. Если я пытаюсь подобрать название, например «Some Fancy Naméa», оно работает просто отлично. Если я уберу слово «якорь» последнего слова, оно будет работать нормально.

Почему здесь не работает флаг границы слова? Любые предложения о том, как бы я обойти эту проблему?

Я подумал об использовании чего-то подобного, но я не уверен, на что будут похожи потери производительности:

"Some fancy namé. Allow me to ellaborate.".replace(/([\s.,!?])(fancy namé|namé)([\s.,!?]|$)/g, '$1<a href="#">$2</a>$3')

Предложения? Идеи?

Ответы [ 5 ]

14 голосов
/ 15 марта 2010

Реализация JavaScript в регулярном выражении не поддерживает Unicode. Он знает только «слово-символы» в стандартном младшем байте ASCII, который не включает é или любые другие акцентированные или неанглийские буквы.

Поскольку é не является символом слова для JS, é, за которым следует пробел, никогда не может считаться границей слова. (Он будет соответствовать \b, если используется в середине слова, например Namés.)

/([\s.,!?])(fancy namé|namé)([\s.,!?]|$)/

Да, это был бы обычный обходной путь для JS (хотя, возможно, с большим количеством знаков препинания). Для других языков вы, как правило, используете lookahead / lookbehind, чтобы избежать совпадения символов до и после границы, но они плохо поддерживаются / содержат ошибки в JS, поэтому их лучше избегать.

7 голосов
/ 15 марта 2010

Роб прав. Цитируется из ECMAScript 3-е издание:

15.10.2.6 Утверждение:

Производство Утверждение \b оценивается по ...

2. Вызовите IsWordChar (e & minus; 1) и пусть a будет логическим результатом
3. Вызовите IsWordChar (e) и пусть b будет логическим результатом

и

Внутренняя вспомогательная функция IsWordChar ... выполняет следующее:

3. Если c является одним из шестидесяти трех символов в таблице ниже, верните true .

a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9 _

Поскольку é не является одним из этих 63 символов, расположение между é и a будет считаться границей слова.

Если вы знаете класс символов, вы можете использовать отрицательное прогнозное утверждение, например,

/(^|[^\wÀ-ÖØ-öø-ſ])(Fancy Namé|Namé)(?![\wÀ-ÖØ-öø-ſ])/
4 голосов
/ 18 ноября 2010

Знай свои границы

К сожалению, даже если и когда-нибудь когда-нибудь Javascript получит полную и правильную поддержку Юникода, вы все равно должны быть очень осторожны с границами слов. Легко понять, что на самом деле делает \b.

Вот код Perl, который объясняет, что на самом деле делает \b, что верно независимо от того, был ли ваш движок шаблонов еще модернизирован в BNM:

  # if next is word char:
  #     then last isn't    word
  #     else last isn't nonword

    $word_boundary_before = qr{ (?(?=  \w ) (?<! \w ) | (?<! \W ) ) }x;

  # if last is word:
  #     then next isn't    word
  #     else next isn't nonword

    $word_boundary_after  = qr{ (?(?<= \w ) (?!  \w ) | (?!  \W ) ) }x;

Первое похоже на \b перед чем-то, а второе - на \b после него. Используемая конструкция является условным выражением «IF-THEN = ELSE», которое имеет общий вид (?(COND)THEN|ELSE). Здесь я использую тест COND , который в первом случае смотрит в будущее, но во втором. Предложения THEN и ELSE в обоих случаях являются отрицательными обходными путями, поэтому они учитывают край строки.

Я объясняю больше о работе с границами и Unicode в регулярных выражениях здесь .

Поддержка свойств Unicode

Текущее состояние дел в отношении обработки Unicode в Javascript кажется таким, как в Java, определения \w в Javascript и так далее до сих пор наносят урон, будучи застрявшими в прошлом в 1960-х мире ASCII. Это просто ужасная ситуация, я признаю. Даже Python, который довольно консервативен в этом отношении (например, он даже не поддерживает рекурсивные регулярные выражения), позволяет разрешать его определениям \w и \s для корректной работы с Unicode. Это минимальный уровень функциональности, на самом деле.

В Javasscript как лучше, так и хуже. Это потому, что вы можете использовать несколько самых базовых свойств Юникода в Javascript (или Java). Похоже, вы должны быть в состоянии использовать однозначные и двухсимвольные свойства Юникода «Общая категория». Это означает, что вы должны использовать короткие версии версий из первого столбца ниже:

Short Name  Long Name
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 \pL        \p{Letter}
   \p{Lu}   \p{Uppercase_Letter}
   \p{Ll}   \p{Lowercase_Letter}
   \p{Lt}   \p{Titlecase_Letter}
   \p{Lm}   \p{Modifier_Letter}
   \p{Lo}   \p{Other_Letter}

Short Name  Long Name
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 \pM       \p{Mark}
   \p{Mn}  \p{Nonspacing_Mark}
   \p{Mc}  \p{Spacing_Mark}
   \p{Me}  \p{Enclosing_Mark}

Short Name  Long Name
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 \pN       \p{Number}
   \p{Nd}  \p{Decimal_Number},\p{Digit}
   \p{Nl}  \p{Letter_Number}
   \p{No}  \p{Other_Number}

Short Name  Long Name
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 \pP       \p{Punctuation}, \p{Punct})
   \p{Pc}  \p{Connector_Punctuation}
   \p{Pd}  \p{Dash_Punctuation}
   \p{Ps}  \p{Open_Punctuation}
   \p{Pe}  \p{Close_Punctuation}
   \p{Pi}  \p{Initial_Punctuation}
   \p{Pf}  \p{Final_Punctuation}
   \p{Po}  \p{Other_Punctuation}

Short Name  Long Name
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 \pS       \p{Symbol}
   \p{Sm}  \p{Math_Symbol}
   \p{Sc}  \p{Currency_Symbol}
   \p{Sk}  \p{Modifier_Symbol}
   \p{So}  \p{Other_Symbol}

Short Name  Long Name
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 \pZ       \p{Separator}
   \p{Zs}  \p{Space_Separator}
   \p{Zl}  \p{Line_Separator}
   \p{Zp}  \p{Paragraph_Separator}

Short Name  Long Name
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
 \pC       \p{Other}
   \p{Cc}  \p{Control}, \p{Cntrl}
   \p{Cf}  \p{Format}
   \p{Cs}  \p{Surrogate}
   \p{Co}  \p{Private_Use}
   \p{Cn}  \p{Unassigned}

Вы должны использовать короткие имена только в Java и Javascript, но Perl позволяет вам также использовать длинные имена, что помогает для разборчивости. В Perl версии 5.12 поддерживается около 3000 свойств Unicode. В Python все еще нет поддержки свойств Unicode, о которой стоит упомянуть, и Ruby только начинает получать ее в версии 1.9. PCRE имеет ограниченную поддержку, в основном как Java 1.7.

Java6 поддерживает свойства блока Unicode, например \p{InGeneralPunctuation} или \p{Block=GeneralPunctuation}, а Java7 поддерживает свойства сценария Unicode, например \p{IsHiragana} или \p{Script=Hiragana}.

Тем не менее, он по-прежнему не поддерживает ничего, даже близкого к полному набору свойств Unicode , в том числе почти критических, таких как \p⁠{WhiteSpace}, \p{Dash} и \p{Quotation_Mark}, не говоря уже о другие два разделителя, такие как \p⁠{Line_Break=Alphabetic}, \p⁠{East_Asian_Width:Narrow}, \p⁠{Numeric_Value=1000} или \p⁠⁠{Age:5.2}.

Первый набор довольно незаменим - , особенно , учитывая отсутствие поддержки \s, работающего правильно - и последний набор иногда чертовски полезен.

Что-то еще, что Java и Javascript еще не поддерживают, это пользовательские свойства символов . Я использую их совсем немного. Таким образом, вы можете определить такие вещи, как \p⁠{English::Vowel} или \p⁠{English::Consonant}, что очень удобно.

Если вас интересуют свойства Unicode для работы с регулярными выражениями, то вам может понадобиться набор программ unitrio : uniprops , unichars и uninames . Вот демонстрация каждого из этих трех:

$ uninames face
 ፦  4966  1366  ETHIOPIC PREFACE COLON
 ⁙  8281  2059  FIVE DOT PUNCTUATION
        = Greek pentonkion
        = quincunx
        x (die face-5 - 2684)
 ∯  8751  222F  SURFACE INTEGRAL
        # 222E 222E
 ☹  9785  2639 WHITE FROWNING FACE
 ☺  9786  263A WHITE SMILING FACE
        = have a nice day!
 ☻  9787  263B BLACK SMILING FACE
 ⚀  9856  2680 DIE FACE-1
 ⚁  9857  2681 DIE FACE-2
 ⚂  9858  2682 DIE FACE-3
 ⚃  9859  2683 DIE FACE-4
 ⚄  9860  2684 DIE FACE-5
 ⚅  9861  2685 DIE FACE-6
 ⾯  12207 2FAF KANGXI RADICAL FACE
        # 9762
 〠  12320 3020 POSTAL MARK FACE
 龜  64206 FACE CJK COMPATIBILITY IDEOGRAPH-FACE
        : 9F9C

FMTEYEWTK о свойствах Юникода:

$ uniprops -va LF 85 Greek:Sigma INFINITY BOM U+3000 U+12345

U+000A ‹U+000A› \N{ LINE FEED (LF) }:
    \s \v \R \pC \p{Cc}
    \p{All} \p{Any} \p{ASCII} \p{Assigned} \p{C} \p{Other} \p{Cc} \p{Cntrl} \p{Common} \p{Zyyy} \p{Control} \p{Pat_WS} \p{Pattern_White_Space} \p{PatWS} \p{PerlSpace} \p{PosixCntrl} \p{PosixSpace} \p{Space} \p{SpacePerl} \p{VertSpace} \p{White_Space} \p{WSpace}
    \p{Age:1.1} \p{Block=Basic_Latin} \p{Bidi_Class:B} \p{Bidi_Class=Paragraph_Separator} \p{Bidi_Class:Paragraph_Separator} \p{Bc=B} \p{Block:ASCII} \p{Block:Basic_Latin} \p{Blk=ASCII} \p{Canonical_Combining_Class:0} \p{Canonical_Combining_Class=Not_Reordered}
       \p{Canonical_Combining_Class:Not_Reordered} \p{Ccc=NR} \p{Canonical_Combining_Class:NR} \p{Script=Common} \p{Decomposition_Type:None} \p{Dt=None} \p{East_Asian_Width=Neutral} \p{East_Asian_Width:Neutral} \p{Grapheme_Cluster_Break:LF} \p{GCB=LF} \p{Hangul_Syllable_Type:NA}
       \p{Hangul_Syllable_Type=Not_Applicable} \p{Hangul_Syllable_Type:Not_Applicable} \p{Hst=NA} \p{Joining_Group:No_Joining_Group} \p{Jg=NoJoiningGroup} \p{Joining_Type:Non_Joining} \p{Jt=U} \p{Joining_Type:U} \p{Joining_Type=Non_Joining} \p{Line_Break:LF} \p{Line_Break=Line_Feed}
       \p{Line_Break:Line_Feed} \p{Lb=LF} \p{Numeric_Type:None} \p{Nt=None} \p{Numeric_Value:NaN} \p{Nv=NaN} \p{Present_In:1.1} \p{Age=1.1} \p{In=1.1} \p{Present_In:2.0} \p{In=2.0} \p{Present_In:2.1} \p{In=2.1} \p{Present_In:3.0} \p{In=3.0} \p{Present_In:3.1} \p{In=3.1}
       \p{Present_In:3.2} \p{In=3.2} \p{Present_In:4.0} \p{In=4.0} \p{Present_In:4.1} \p{In=4.1} \p{Present_In:5.0} \p{In=5.0} \p{Present_In:5.1} \p{In=5.1} \p{Present_In:5.2} \p{In=5.2} \p{Script:Common} \p{Sc=Zyyy} \p{Script:Zyyy} \p{Sentence_Break:LF} \p{SB=LF} \p{Word_Break:LF}
       \p{WB=LF}

U+0085 ‹U+0085› \N{ NEXT LINE (NEL) }:
    \s \v \R \pC \p{Cc}
    \p{All} \p{Any} \p{Assigned} \p{InLatin1} \p{C} \p{Other} \p{Cc} \p{Cntrl} \p{Common} \p{Zyyy} \p{Control} \p{Pat_WS} \p{Pattern_White_Space} \p{PatWS} \p{Space} \p{SpacePerl} \p{VertSpace} \p{White_Space} \p{WSpace}
    \p{Age:1.1} \p{Bidi_Class:B} \p{Bidi_Class=Paragraph_Separator} \p{Bidi_Class:Paragraph_Separator} \p{Bc=B} \p{Block:Latin_1} \p{Block=Latin_1_Supplement} \p{Block:Latin_1_Supplement} \p{Blk=Latin1} \p{Canonical_Combining_Class:0} \p{Canonical_Combining_Class=Not_Reordered}
       \p{Canonical_Combining_Class:Not_Reordered} \p{Ccc=NR} \p{Canonical_Combining_Class:NR} \p{Script=Common} \p{Decomposition_Type:None} \p{Dt=None} \p{East_Asian_Width=Neutral} \p{East_Asian_Width:Neutral} \p{Grapheme_Cluster_Break:CN} \p{Grapheme_Cluster_Break=Control}
       \p{Grapheme_Cluster_Break:Control} \p{GCB=CN} \p{Hangul_Syllable_Type:NA} \p{Hangul_Syllable_Type=Not_Applicable} \p{Hangul_Syllable_Type:Not_Applicable} \p{Hst=NA} \p{Joining_Group:No_Joining_Group} \p{Jg=NoJoiningGroup} \p{Joining_Type:Non_Joining} \p{Jt=U}
       \p{Joining_Type:U} \p{Joining_Type=Non_Joining} \p{Line_Break:Next_Line} \p{Lb=NL} \p{Line_Break:NL} \p{Line_Break=Next_Line} \p{Numeric_Type:None} \p{Nt=None} \p{Numeric_Value:NaN} \p{Nv=NaN} \p{Present_In:1.1} \p{Age=1.1} \p{In=1.1} \p{Present_In:2.0} \p{In=2.0}
       \p{Present_In:2.1} \p{In=2.1} \p{Present_In:3.0} \p{In=3.0} \p{Present_In:3.1} \p{In=3.1} \p{Present_In:3.2} \p{In=3.2} \p{Present_In:4.0} \p{In=4.0} \p{Present_In:4.1} \p{In=4.1} \p{Present_In:5.0} \p{In=5.0} \p{Present_In:5.1} \p{In=5.1} \p{Present_In:5.2} \p{In=5.2}
       \p{Script:Common} \p{Sc=Zyyy} \p{Script:Zyyy} \p{Sentence_Break:SE} \p{Sentence_Break=Sep} \p{Sentence_Break:Sep} \p{SB=SE} \p{Word_Break:Newline} \p{WB=NL} \p{Word_Break:NL} \p{Word_Break=Newline}

U+03A3 ‹Σ› \N{ GREEK CAPITAL LETTER SIGMA }:
    \w \pL} \p{LC} \p{L_} \p{L&} \p{Lu}
    \p{All} \p{Any} \p{Alnum} \p{Alpha} \p{Alphabetic} \p{Assigned} \p{Greek} \p{Is_Greek} \p{InGreek} \p{Cased} \p{Cased_Letter} \p{LC} \p{Changes_When_Casefolded} \p{CWCF} \p{Changes_When_Casemapped} \p{CWCM} \p{Changes_When_Lowercased} \p{CWL} \p{Changes_When_NFKC_Casefolded}
       \p{CWKCF} \p{Lu} \p{L} \p{Gr_Base} \p{Grapheme_Base} \p{Graph} \p{GrBase} \p{Grek} \p{Greek_And_Coptic} \p{ID_Continue} \p{IDC} \p{ID_Start} \p{IDS} \p{Letter} \p{L_} \p{Uppercase_Letter} \p{Print} \p{Upper} \p{Uppercase} \p{Word} \p{XID_Continue} \p{XIDC} \p{XID_Start}
       \p{XIDS}
    \p{Age:1.1} \p{Bidi_Class:L} \p{Bidi_Class=Left_To_Right} \p{Bidi_Class:Left_To_Right} \p{Bc=L} \p{Block:Greek} \p{Block=Greek_And_Coptic} \p{Block:Greek_And_Coptic} \p{Blk=Greek} \p{Canonical_Combining_Class:0} \p{Canonical_Combining_Class=Not_Reordered}
       \p{Canonical_Combining_Class:Not_Reordered} \p{Ccc=NR} \p{Canonical_Combining_Class:NR} \p{Decomposition_Type:None} \p{Dt=None} \p{East_Asian_Width:A} \p{East_Asian_Width=Ambiguous} \p{East_Asian_Width:Ambiguous} \p{Ea=A} \p{Grapheme_Cluster_Break:Other} \p{GCB=XX}
       \p{Grapheme_Cluster_Break:XX} \p{Grapheme_Cluster_Break=Other} \p{Script=Greek} \p{Hangul_Syllable_Type:NA} \p{Hangul_Syllable_Type=Not_Applicable} \p{Hangul_Syllable_Type:Not_Applicable} \p{Hst=NA} \p{Joining_Group:No_Joining_Group} \p{Jg=NoJoiningGroup}
       \p{Joining_Type:Non_Joining} \p{Jt=U} \p{Joining_Type:U} \p{Joining_Type=Non_Joining} \p{Line_Break:AL} \p{Line_Break=Alphabetic} \p{Line_Break:Alphabetic} \p{Lb=AL} \p{Numeric_Type:None} \p{Nt=None} \p{Numeric_Value:NaN} \p{Nv=NaN} \p{Present_In:1.1} \p{Age=1.1} \p{In=1.1}
       \p{Present_In:2.0} \p{In=2.0} \p{Present_In:2.1} \p{In=2.1} \p{Present_In:3.0} \p{In=3.0} \p{Present_In:3.1} \p{In=3.1} \p{Present_In:3.2} \p{In=3.2} \p{Present_In:4.0} \p{In=4.0} \p{Present_In:4.1} \p{In=4.1} \p{Present_In:5.0} \p{In=5.0} \p{Present_In:5.1} \p{In=5.1}
       \p{Present_In:5.2} \p{In=5.2} \p{Script:Greek} \p{Sc=Grek} \p{Script:Grek} \p{Sentence_Break:UP} \p{Sentence_Break=Upper} \p{Sentence_Break:Upper} \p{SB=UP} \p{Word_Break:ALetter} \p{WB=LE} \p{Word_Break:LE} \p{Word_Break=ALetter}

U+221E ‹∞› \N{ INFINITY }:
    \pS \p{Sm}
    \p{All} \p{Any} \p{Assigned} \p{InMathematicalOperators} \p{Common} \p{Zyyy} \p{Sm} \p{S} \p{Gr_Base} \p{Grapheme_Base} \p{Graph} \p{GrBase} \p{Math} \p{Math_Symbol} \p{Pat_Syn} \p{Pattern_Syntax} \p{PatSyn} \p{Print} \p{Symbol}
    \p{Age:1.1} \p{Bidi_Class:ON} \p{Bidi_Class=Other_Neutral} \p{Bidi_Class:Other_Neutral} \p{Bc=ON} \p{Block:Mathematical_Operators} \p{Canonical_Combining_Class:0} \p{Canonical_Combining_Class=Not_Reordered} \p{Canonical_Combining_Class:Not_Reordered} \p{Ccc=NR}
       \p{Canonical_Combining_Class:NR} \p{Script=Common} \p{Decomposition_Type:None} \p{Dt=None} \p{East_Asian_Width:A} \p{East_Asian_Width=Ambiguous} \p{East_Asian_Width:Ambiguous} \p{Ea=A} \p{Grapheme_Cluster_Break:Other} \p{GCB=XX} \p{Grapheme_Cluster_Break:XX}
       \p{Grapheme_Cluster_Break=Other} \p{Hangul_Syllable_Type:NA} \p{Hangul_Syllable_Type=Not_Applicable} \p{Hangul_Syllable_Type:Not_Applicable} \p{Hst=NA} \p{Joining_Group:No_Joining_Group} \p{Jg=NoJoiningGroup} \p{Joining_Type:Non_Joining} \p{Jt=U} \p{Joining_Type:U}
       \p{Joining_Type=Non_Joining} \p{Line_Break:AI} \p{Line_Break=Ambiguous} \p{Line_Break:Ambiguous} \p{Lb=AI} \p{Numeric_Type:None} \p{Nt=None} \p{Numeric_Value:NaN} \p{Nv=NaN} \p{Present_In:1.1} \p{Age=1.1} \p{In=1.1} \p{Present_In:2.0} \p{In=2.0} \p{Present_In:2.1} \p{In=2.1}
       \p{Present_In:3.0} \p{In=3.0} \p{Present_In:3.1} \p{In=3.1} \p{Present_In:3.2} \p{In=3.2} \p{Present_In:4.0} \p{In=4.0} \p{Present_In:4.1} \p{In=4.1} \p{Present_In:5.0} \p{In=5.0} \p{Present_In:5.1} \p{In=5.1} \p{Present_In:5.2} \p{In=5.2} \p{Script:Common} \p{Sc=Zyyy}
       \p{Script:Zyyy} \p{Sentence_Break:Other} \p{SB=XX} \p{Sentence_Break:XX} \p{Sentence_Break=Other} \p{Word_Break:Other} \p{WB=XX} \p{Word_Break:XX} \p{Word_Break=Other}

U+FEFF ‹U+FEFF› \N{ ZERO WIDTH NO-BREAK SPACE }:
    \pC \p{Cf}
    \p{All} \p{Any} \p{Assigned} \p{InArabicPresentationFormsB} \p{C} \p{Other} \p{Case_Ignorable} \p{CI} \p{Cf} \p{Format} \p{Changes_When_NFKC_Casefolded} \p{CWKCF} \p{Common} \p{Zyyy} \p{Default_Ignorable_Code_Point} \p{DI} \p{Graph} \p{Print}
    \p{Age:1.1} \p{Bidi_Class:BN} \p{Bidi_Class=Boundary_Neutral} \p{Bidi_Class:Boundary_Neutral} \p{Bc=BN} \p{Block:Arabic_Presentation_Forms_B} \p{Canonical_Combining_Class:0} \p{Canonical_Combining_Class=Not_Reordered} \p{Canonical_Combining_Class:Not_Reordered} \p{Ccc=NR}
       \p{Canonical_Combining_Class:NR} \p{Script=Common} \p{Decomposition_Type:None} \p{Dt=None} \p{East_Asian_Width=Neutral} \p{East_Asian_Width:Neutral} \p{Grapheme_Cluster_Break:CN} \p{Grapheme_Cluster_Break=Control} \p{Grapheme_Cluster_Break:Control} \p{GCB=CN}
       \p{Hangul_Syllable_Type:NA} \p{Hangul_Syllable_Type=Not_Applicable} \p{Hangul_Syllable_Type:Not_Applicable} \p{Hst=NA} \p{Joining_Group:No_Joining_Group} \p{Jg=NoJoiningGroup} \p{Joining_Type:T} \p{Joining_Type=Transparent} \p{Joining_Type:Transparent} \p{Jt=T}
       \p{Line_Break:WJ} \p{Line_Break=Word_Joiner} \p{Line_Break:Word_Joiner} \p{Lb=WJ} \p{Numeric_Type:None} \p{Nt=None} \p{Numeric_Value:NaN} \p{Nv=NaN} \p{Present_In:1.1} \p{Age=1.1} \p{In=1.1} \p{Present_In:2.0} \p{In=2.0} \p{Present_In:2.1} \p{In=2.1} \p{Present_In:3.0}
       \p{In=3.0} \p{Present_In:3.1} \p{In=3.1} \p{Present_In:3.2} \p{In=3.2} \p{Present_In:4.0} \p{In=4.0} \p{Present_In:4.1} \p{In=4.1} \p{Present_In:5.0} \p{In=5.0} \p{Present_In:5.1} \p{In=5.1} \p{Present_In:5.2} \p{In=5.2} \p{Script:Common} \p{Sc=Zyyy} \p{Script:Zyyy}
       \p{Sentence_Break:FO} \p{Sentence_Break=Format} \p{Sentence_Break:Format} \p{SB=FO} \p{Word_Break:FO} \p{Word_Break=Format} \p{Word_Break:Format} \p{WB=FO}

U+3000 ‹U+3000› \N{ IDEOGRAPHIC SPACE }:
    \s \h \pZ \p{Zs}
    \p{All} \p{Any} \p{Assigned} \p{Blank} \p{InCJKSymbolsAndPunctuation} \p{Changes_When_NFKC_Casefolded} \p{CWKCF} \p{Common} \p{Zyyy} \p{Z} \p{Zs} \p{Gr_Base} \p{Grapheme_Base} \p{GrBase} \p{HorizSpace} \p{Print} \p{Separator} \p{Space} \p{Space_Separator} \p{SpacePerl}
       \p{White_Space} \p{WSpace}
    \p{Age:1.1} \p{Bidi_Class:White_Space} \p{Bc=WS} \p{Bidi_Class:WS} \p{Bidi_Class=White_Space} \p{Block:CJK_Symbols_And_Punctuation} \p{Canonical_Combining_Class:0} \p{Canonical_Combining_Class=Not_Reordered} \p{Canonical_Combining_Class:Not_Reordered} \p{Ccc=NR}
       \p{Canonical_Combining_Class:NR} \p{Script=Common} \p{Decomposition_Type:Non_Canon} \p{Decomposition_Type=Non_Canonical} \p{Decomposition_Type:Non_Canonical} \p{Dt=NonCanon} \p{Decomposition_Type:Wide} \p{Dt=Wide} \p{East_Asian_Width:F} \p{East_Asian_Width=Fullwidth}
       \p{East_Asian_Width:Fullwidth} \p{Ea=F} \p{Grapheme_Cluster_Break:Other} \p{GCB=XX} \p{Grapheme_Cluster_Break:XX} \p{Grapheme_Cluster_Break=Other} \p{Hangul_Syllable_Type:NA} \p{Hangul_Syllable_Type=Not_Applicable} \p{Hangul_Syllable_Type:Not_Applicable} \p{Hst=NA}
       \p{Joining_Group:No_Joining_Group} \p{Jg=NoJoiningGroup} \p{Joining_Type:Non_Joining} \p{Jt=U} \p{Joining_Type:U} \p{Joining_Type=Non_Joining} \p{Line_Break:ID} \p{Line_Break=Ideographic} \p{Line_Break:Ideographic} \p{Lb=ID} \p{Numeric_Type:None} \p{Nt=None}
       \p{Numeric_Value:NaN} \p{Nv=NaN} \p{Present_In:1.1} \p{Age=1.1} \p{In=1.1} \p{Present_In:2.0} \p{In=2.0} \p{Present_In:2.1} \p{In=2.1} \p{Present_In:3.0} \p{In=3.0} \p{Present_In:3.1} \p{In=3.1} \p{Present_In:3.2} \p{In=3.2} \p{Present_In:4.0} \p{In=4.0} \p{Present_In:4.1}
       \p{In=4.1} \p{Present_In:5.0} \p{In=5.0} \p{Present_In:5.1} \p{In=5.1} \p{Present_In:5.2} \p{In=5.2} \p{Script:Common} \p{Sc=Zyyy} \p{Script:Zyyy} \p{Sentence_Break:Sp} \p{SB=Sp} \p{Word_Break:Other} \p{WB=XX} \p{Word_Break:XX} \p{Word_Break=Other}

U+12345 ‹?› \N{ CUNEIFORM SIGN URU TIMES KI }:
    \w} \p{\pL} \p{L_} \p{Lo}
    \p{All} \p{Any} \p{Alnum} \p{Alpha} \p{Alphabetic} \p{Assigned} \p{InCuneiform} \p{Cuneiform} \p{Is_Cuneiform} \p{Xsux} \p{L} \p{Lo} \p{Gr_Base} \p{Grapheme_Base} \p{Graph} \p{GrBase} \p{ID_Continue} \p{IDC} \p{ID_Start} \p{IDS} \p{Letter} \p{L_} \p{Other_Letter} \p{Print}
       \p{Word} \p{XID_Continue} \p{XIDC} \p{XID_Start} \p{XIDS}
    \p{Age:5.0} \p{Bidi_Class:L} \p{Bidi_Class=Left_To_Right} \p{Bidi_Class:Left_To_Right} \p{Bc=L} \p{Block:Cuneiform} \p{Canonical_Combining_Class:0} \p{Canonical_Combining_Class=Not_Reordered} \p{Canonical_Combining_Class:Not_Reordered} \p{Ccc=NR}
       \p{Canonical_Combining_Class:NR} \p{Script=Cuneiform} \p{Block=Cuneiform} \p{Decomposition_Type:None} \p{Dt=None} \p{East_Asian_Width=Neutral} \p{East_Asian_Width:Neutral} \p{Grapheme_Cluster_Break:Other} \p{GCB=XX} \p{Grapheme_Cluster_Break:XX}
       \p{Grapheme_Cluster_Break=Other} \p{Hangul_Syllable_Type:NA} \p{Hangul_Syllable_Type=Not_Applicable} \p{Hangul_Syllable_Type:Not_Applicable} \p{Hst=NA} \p{Joining_Group:No_Joining_Group} \p{Jg=NoJoiningGroup} \p{Joining_Type:Non_Joining} \p{Jt=U} \p{Joining_Type:U}
       \p{Joining_Type=Non_Joining} \p{Line_Break:AL} \p{Line_Break=Alphabetic} \p{Line_Break:Alphabetic} \p{Lb=AL} \p{Numeric_Type:None} \p{Nt=None} \p{Numeric_Value:NaN} \p{Nv=NaN} \p{Present_In:5.0} \p{In=5.0} \p{Present_In:5.1} \p{In=5.1} \p{Present_In:5.2} \p{In=5.2}
       \p{Script:Cuneiform} \p{Sc=Xsux} \p{Script:Xsux} \p{Sentence_Break:LE} \p{Sentence_Break=OLetter} \p{Sentence_Break:OLetter} \p{SB=LE} \p{Word_Break:ALetter} \p{WB=LE} \p{Word_Break:LE} \p{Word_Break=ALetter}

Или, идя другим путем:

$ unichars '\pN' '\D' '\p{Latin}'
 Ⅰ      8544  02160  ROMAN NUMERAL ONE
 Ⅱ      8545  02161  ROMAN NUMERAL TWO
 Ⅲ      8546  02162  ROMAN NUMERAL THREE
 Ⅳ      8547  02163  ROMAN NUMERAL FOUR
 Ⅴ      8548  02164  ROMAN NUMERAL FIVE
 Ⅵ      8549  02165  ROMAN NUMERAL SIX
 Ⅶ      8550  02166  ROMAN NUMERAL SEVEN
 Ⅷ      8551  02167  ROMAN NUMERAL EIGHT
 (etc)

$ unichars -a '\pL' '\p{Greek}' 'NFD ne NFKD' 'NAME =~ /SYMBOL/'
 ϐ       976  3D0  GREEK BETA SYMBOL
 ϑ       977  3D1  GREEK THETA SYMBOL
 ϒ       978  3D2  GREEK UPSILON WITH HOOK SYMBOL
 ϓ       979  3D3  GREEK UPSILON WITH ACUTE AND HOOK SYMBOL
 ϔ       980  3D4  GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL
 ϕ       981  3D5  GREEK PHI SYMBOL
 ϖ       982  3D6  GREEK PI SYMBOL
 ϰ      1008  3F0  GREEK KAPPA SYMBOL
 ϱ      1009  3F1  GREEK RHO SYMBOL
 ϲ      1010  3F2  GREEK LUNATE SIGMA SYMBOL
 ϴ      1012  3F4  GREEK CAPITAL THETA SYMBOL
 ϵ      1013  3F5  GREEK LUNATE EPSILON SYMBOL
 Ϲ      1017  3F9  GREEK CAPITAL LUNATE SIGMA SYMBOL

Да, и БНМ означает «Храброе новое тысячелетие» , относящееся к нашему современному миру после ASCII, в котором символы имеют ширину более семи мельчайших битов. ☺

1 голос
/ 19 июля 2010

String.replace () принимает функцию обратного вызова в качестве второго параметра.(Не знаю, почему во многих руководствах по JS эта полезная функция не указана.) Таким образом, мы можем написать наш собственный тест для границ слов.

Решение, предложенное в другом месте, с regexp /(\W|^)(fancy namé|namé)(\W|$)/ig, дает ложные срабатывания в случаяхтекста, такого как 'naméé'.

String.prototype.isWordCharAt = function(i) {
    // should work for European languages and Unicode
    return (this.charAt(i) >= 'A' && this.charAt(i) <= 'Z')
        || (this.charAt(i) >= 'a' && this.charAt(i) <= 'z')
        || (this.charCodeAt(i) >= 0xC0 && this.charCodeAt(i) < 0x2000)
    ;
};

"Namé. Goal: Some Fancy Namé. Namé. Nénamé. Namée. Nénamée. Namé"
.replace(/(Namé|Fancy Namé)/ig, function(
match, part1, /* part2, part3, ... */ offset, fullText) {
  // Keep in mind that the number of arguments changes
  // if the number of capturing parenthesis in regexp changes.
  // We could use 'arguments' pseudo-array instead.
  var len1 = part1.length;
  var leftWordBoundary;
  var rightWordBoundary;

  if (offset === 0) {
    leftWordBoundary = fullText.isWordCharAt(offset);
  }
  else {
    leftWordBoundary = (fullText.isWordCharAt(offset - 1)
      != fullText.isWordCharAt(offset));
  }

  if (offset + len1 == fullText.length) {
    rightWordBoundary = fullText.isWordCharAt(offset + len1 - 1);
  }
  else {
    rightWordBoundary = (fullText.isWordCharAt(offset + len1 - 1)
      != fullText.isWordCharAt(offset + len1));
  }

  if (leftWordBoundary && rightWordBoundary) {
    return '<a href="#">' + part1 + '</a>';
  }
  else {
    return part1;
  }
});
0 голосов
/ 15 марта 2010

Возможно, попробуйте использовать флаги \o или \x при использовании вашего регулярного выражения.

Конец эта ссылка для регулярных выражений Javascript может вам помочь.

Что касается фактических восьмеричных / шестнадцатеричных значений é, я не уверен.

...