CakeFest 2024: The Official CakePHP Conference

Unicode 文字プロパティ

PHP 5.1.0 以降、UTF-8 モード を設定した場合に、 一般的な文字タイプにマッチする新たなエスケープシーケンスが 3 つ追加されました。

\p{xx}
xx プロパティを持つ文字
\P{xx}
xx プロパティを持たない文字
\X
拡張 Unicode シーケンス

ここで xx で表されているプロパティ名は、Unicode で 一般カテゴリプロパティ (general category properties) として規定されているものに なります。すべての文字は、いずれかひとつのプロパティを持ちます。 プロパティは、2 文字の略語で表されます。Perl と同じく、 開き波カッコとプロパティ名との間にハット文字を記述することで否定を指定できます。 たとえば、\p{^Lu}\P{Lu} と同じです。

\p もしくは \P の後に、一文字だけを記述すると その文字で始まるすべてのプロパティが指定されたことになります。 この場合、否定の指定をしていない場合、波カッコを使用しなくても構いません。 以下の 2 つの例は等価になります。

\p{L}
\pL
使用可能なプロパティコード
プロパティ マッチ 備考
C その他 (Other)  
Cc コントロール文字 (Control)  
Cf 非可視整形用文字 (Format)  
Cn 未定義コードポイント (Unassigned)  
Co 私的利用領域 (Private use)  
Cs サロゲート (Surrogate)  
L アルファベット (Letter) LlLmLoLt および Lu を含む
Ll 小文字アルファベット (Lower case letter)  
Lm 擬似文字 (Modifier letter)  
Lo その他の文字 (Other letter)  
Lt タイトル文字 (Title case letter)  
Lu 大文字アルファベット (Upper case letter)  
M 記号 (Mark)  
Mc 修飾文字 (Spacing mark)  
Me 他の文字を囲むための文字 (Enclosing mark)  
Mn 他の文字を修飾するための文字 (Non-spacing mark)  
N 数字 (Number)  
Nd 10 進数字 (Decimal number)  
Nl 数値を表す文字 (Letter number)  
No その他の数字 (Other number)  
P 句読記号 (Punctuation)  
Pc 連結用句読記号 (Connector punctuation)  
Pd ダッシュ (Dash punctuation)  
Pe 閉じ句読記号 (Close punctuation)  
Pf 末尾句読記号 (Final punctuation)  
Pi 先頭句読記号 (Initial punctuation)  
Po その他の句読記号 (Other punctuation)  
Ps 開き句読記号 (Open punctuation)  
S 記号 (Symbol)  
Sc 通貨記号 (Currency symbol)  
Sk 合わせ文字 (Modifier symbol)  
Sm 数学記号 (Mathematical symbol)  
So その他の記号 (Other symbol)  
Z 区切り文字 (Separator)  
Zl 行区切り文字 (Line separator)  
Zp 段落区切り文字 (Paragraph separator)  
Zs 空白文字 (Space separator)  

InMusicalSymbols のような拡張プロパティ (extended properties) を、PCRE はサポートしていません。

大小文字を区別しないマッチングを設定していても、これらのエスケープ シーケンスには影響しません。たとえば、\p{Lu} は 常に大文字にのみマッチします。

Unicode の文字は、何らかのスクリプトに属するものとして定義されています。 スクリプト名を指定すれば、そのスクリプトの文字群の一文字にマッチさせることができます。 たとえば、次のように使います。

  • \p{Greek}
  • \P{Han}

どのスクリプトにも属しない文字は、ぜんぶまとめて Common で表します。現在サポートするスクリプトは次のとおりです。

サポートするスクリプト
Arabic Armenian Avestan Balinese Bamum
Batak Bengali Bopomofo Brahmi Braille
Buginese Buhid Canadian_Aboriginal Carian Chakma
Cham Cherokee Common Coptic Cuneiform
Cypriot Cyrillic Deseret Devanagari Egyptian_Hieroglyphs
Ethiopic Georgian Glagolitic Gothic Greek
Gujarati Gurmukhi Han Hangul Hanunoo
Hebrew Hiragana Imperial_Aramaic Inherited Inscriptional_Pahlavi
Inscriptional_Parthian Javanese Kaithi Kannada Katakana
Kayah_Li Kharoshthi Khmer Lao Latin
Lepcha Limbu Linear_B Lisu Lycian
Lydian Malayalam Mandaic Meetei_Mayek Meroitic_Cursive
Meroitic_Hieroglyphs Miao Mongolian Myanmar New_Tai_Lue
Nko Ogham Old_Italic Old_Persian Old_South_Arabian
Old_Turkic Ol_Chiki Oriya Osmanya Phags_Pa
Phoenician Rejang Runic Samaritan Saurashtra
Sharada Shavian Sinhala Sora_Sompeng Sundanese
Syloti_Nagri Syriac Tagalog Tagbanwa Tai_Le
Tai_Tham Tai_Viet Takri Tamil Telugu
Thaana Thai Tibetan Tifinagh Ugaritic
Vai Yi        

\X は、Unicode 拡張書記素クラスタにマッチします。 拡張書記素クラスタとは、ひとつあるいは複数の Unicode 文字の組み合わせで単一のグリフを構成するものです。 事実上、これは Unicode 版の . だと考えてかまいません。 その文字をレンダリングするために実際に何文字が使われているかは考えずに、ひとつの合成文字に対応します。

8.32 より古いバージョンの PCRE (これは、組み込みの PCRE ライブラリを使っている場合には PHP 5.4.14 より前のバージョンにあたります) では、 \X(?>\PM\pM*) と等価です。 つまり、記号 (mark) プロパティの付いていない文字と、その後に続く 0 以上の 記号プロパティ付きの文字にマッチし、その並びをアトミック (atomic) な まとまりとして取り扱います。記号プロパティ付きの文字とは、アクセント記号などの 直前の文字に対して影響するようなもののことです。

Unicode プロパティを使った文字列マッチングは速くありません。PCRE は 15,000 以上のデータからなるデータ構造を検索する必要が有るためです。 そのため、PCRE では、\d\w といった 以前から有るエスケープシーケンスは Unicode プロパティを使用しないように なっています。

add a note

User Contributed Notes 10 notes

up
16
huhwatnouDONTspamPLEASE at hotmail dot com
8 years ago
To select UTF-8 mode for the additional escape sequences (\p{xx}, \P{xx}, and \X) , use the "u" modifier (see http://php.net/manual/en/reference.pcre.pattern.modifiers.php).

I wondered why a German sharp S (ß) was marked as a control character by \p{Cc} and it took me a while to properly read the first sentence: "Since 5.1.0, three additional escape sequences to match generic character types are available when UTF-8 mode is selected. " :-$ and then to find out how to do so.
up
3
Steve
7 months ago
Examples are always useful! See https://unicodeplus.com/category for more.

C Other
Cc Control (Unicode code points in the ranges U+0000-U+001F and U+007F-U+009F)
Cf Format (Soft hyphen (U+00AD), zero width space (U+200B), etc.)
Cn Unassigned (Any code point that is not in the Unicode table)
Co Private use
Cs Surrogate (Characters in the range U+D800 to U+DFFF, which are invalid in utf-8)

L Letter
Ll Lower case letter (a-z, µßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ and more)
Lm Modifier letter (Letter-like characters that are usually combined with others, but here they stand alone:
ʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀˁˆˇˈˉˊˋˌˍˎˏːˑˠˡˢˣˤˬˮʹͺՙ and more)
Lo Other letter (ªºƻǀǁǂǃʔ and many more ideographs and letters from unicase alphabets)
Lt Title case letter (DžLjNjDzᾈᾉᾊᾋᾌᾍᾎᾏᾘᾙᾚᾛᾜᾝᾞᾟᾨᾩᾪᾫᾬᾭᾮᾯᾼῌῼ)
Lu Upper case letter (A-Z, ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ and more)
L& Ordinary letter (Any character that has the Lu, Ll, or Lt property)

M Mark
Mc Spacing mark (None in latin scripts)
Me Enclosing mark (Combining enclosing square (U+20DE) like in a⃞ , combining enclosing circle backslash (U+20E0) like in a⃠)
Mn Non-spacing mark (Combining diacritical marks U+0300-U+036f, like the accents on this letter a: áâãāa̅ăȧäảåa̋ǎa̍a̎ȁa̐ȃ)

N Number
Nd Decimal number (0123456789, ٠١٢٣٤٥٦٧٨٩ and digits in many other scripts.)
Nl Letter number (ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿ and some more)
No Other number (⁰¹²³⁴⁵⁶⁷⁸⁹ ₀₁₂₃₄₅₆₇₈₉ ½⅓⅔¼¾⅕⅖⅗⅘⅙⅚⅐⅛⅜⅝⅞⅑⅒ ①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳, etc.)

P Punctuation
Pc Connector punctuation (_ underscore (U+005F), ‿ undertie U+203F, ⁀ character tie (U+2040), etc.)
Pd Dash punctuation (- hyphen-minus (U+002D), ‐ hyphen (U+2010), ‑ non-breaking hyphen (U+2011), ‒ figure dash (U+2012),
– en dash (U+2013), — em dash (U+2014), ― horizontal bar (U+2015), etc.)
Pe Close punctuation (right parenthesis, bracket, or brace: `)` (U+0029), `]` (U+005D), `}` (U+007D), etc.)
Pf Final punctuation (right quotation marks: » (U+00BB), ’ (U+2019), ” (U+201D), etc.)
Pi Initial punctuation (left quotation marks: « (U+00AB), ‘ (U+2018), “ (U+201C), etc.)
Po Other punctuation (!"#%&'*,./:;?@\¡§¶·¿)
Ps Open punctuation (left parenthesis, bracket, or brace: `(` (U+0028), `[` (U+005B), `{` (U+007B), etc.)

S Symbol
Sc Currency symbol ($¢£¤¥, ₠ ₡ ₢ ₣ ₤ ₥ ₦ ₧ ₨ ₩ ₪ ₫ € ₭ ₮ ₯ ₰ ₱ ₲ ₳ ₴ ₵ ₶ ₷ ₸ ₹ ₺ ₻ ₼ ₽ ₾ ₿ (U+20A0-U+20BF), etc.)
Sk Modifier symbol (Symbol-like characters that are usually combined with others, but here they stand alone:
^`¨¯´¸ and more)
Sm Mathematical symbol (+<=>|~¬±×÷϶ and many more)
So Other symbol (¦ broken bar (U+00A6), © copyright sign (U+00A9), ® registered sign (U+00AE), ° degree sign (U+00B0);
arrows, signs, emojis and many many more)

Z Separator
Zl Line separator (line separator (U+2028))
Zp Paragraph separator (paragraph separator (U+2029))
Zs Space separator (space, no-break space, en quad, em quad, en space, em space, figure space, thin space, hair space, etc.)
up
10
mercury at caucasus dot net
13 years ago
An excellent article explaining all these properties can be found here: http://www.regular-expressions.info/unicode.html
up
8
xuantoaiph at gmail dot com
10 years ago
My country, Vietnam, have our own alphabet table:
http://en.wikipedia.org/wiki/Vietnamese_alphabet
I hope PHP will support better than in Vietnamese.
up
3
o_shes01 at uni-muenster dot de
13 years ago
For those who wonder: 'letter_titlecase' applies to digraphs/trigraphs, where capitalization involves only the first letter.
For example, there are three codepoints for the "LJ" digraph in Unicode:
(*) uppercase "LJ": U+01C7
(*) titlecase "Lj": U+01C8
(*) lowercase "lj": U+01C9
up
2
suit at rebell dot at
14 years ago
these properties are usualy only available if PCRE is compiled with "--enable-unicode-properties"

if you want to match any word but want to provide a fallback, you can do something like that:

<?php
if(@preg_match_all('/\p{L}+/u', $str, $arr) {
// fallback goes here
// for example just '/\w+/u' for a less acurate match
}
?>
up
0
php at lnx-bsp dot net
6 years ago
Not made clear in the top of page explanation, but these escaped character classes can be included within square brackets to make a broader character class. For example:

<?php preg_match( '/[\p{N}\p{L}]+/', $data ) ?>

Will match any combination of letters and numbers.
up
0
Yzmir Ramirez
10 years ago
If you are working with older environments you will need to first check to see if the version of PCRE will work with unicode directives described above:

<?php

// Need to check PCRE version because some environments are
// running older versions of the PCRE library
// (run in *nix environment `pcretest -C`)

$allowInternational = false;
if (
defined('PCRE_VERSION')) {
if (
intval(PCRE_VERSION) >= 7) { // constant available since PHP 5.2.4
$allowInternational = true;
}
}
?>

Now you can do a fallback regex (e.g. use "/[a-z]/i"), when the PCRE library version is too old or not available.
up
-5
o_shes01 at uni-muenster dot de
13 years ago
For those who wonder: 'letter_titlecase' applies to digraphs/trigraphs, where capitalization involves only the first letter.
For example, there are three codepoints for the "LJ" digraph in Unicode:
(*) uppercase "LJ": U+01C7
(*) titlecase "Lj": U+01C8
(*) lowercase "lj": U+01C9
up
-3
phpnet at N_O_S_P_A_M dot osps dot net
1 year ago
I found the predefined "supported" scripts helpful, except that there's no apparent definition of what Unicode character ranges are covered by those definitions. So I wrote this to determine them and print out the equivalent PCRE character class definitions. An example fragment of output is (I can't include all output due to PHP.net Note-posting limits)

Canadian_Aboriginal=[\x{1400}-\x{167f}\x{18b0}-\x{18f5}]

The program:

<?php

$scriptNames
= array(
'Arabic',
'Armenian',
'Avestan',
'Balinese',
'Bamum',
'Batak',
'Bengali',
'Bopomofo',
'Brahmi',
'Braille',
'Buginese',
'Buhid',
'Canadian_Aboriginal',
'Carian',
'Chakma',
'Cham',
'Cherokee',
'Common',
'Coptic',
'Cuneiform',
'Cypriot',
'Cyrillic',
'Deseret',
'Devanagari',
'Egyptian_Hieroglyphs',
'Ethiopic',
'Georgian',
'Glagolitic',
'Gothic',
'Greek',
'Gujarati',
'Gurmukhi',
'Han',
'Hangul',
'Hanunoo',
'Hebrew',
'Hiragana',
'Imperial_Aramaic',
'Inherited',
'Inscriptional_Pahlavi',
'Inscriptional_Parthian',
'Javanese',
'Kaithi',
'Kannada',
'Katakana',
'Kayah_Li',
'Kharoshthi',
'Khmer',
'Lao',
'Latin',
'Lepcha',
'Limbu',
'Linear_B',
'Lisu',
'Lycian',
'Lydian',
'Malayalam',
'Mandaic',
'Meetei_Mayek',
'Meroitic_Cursive',
'Meroitic_Hieroglyphs',
'Miao',
'Mongolian',
'Myanmar',
'New_Tai_Lue',
'Nko',
'Ogham',
'Old_Italic',
'Old_Persian',
'Old_South_Arabian',
'Old_Turkic',
'Ol_Chiki',
'Oriya',
'Osmanya',
'Phags_Pa',
'Phoenician',
'Rejang',
'Runic',
'Samaritan',
'Saurashtra',
'Sharada',
'Shavian',
'Sinhala',
'Sora_Sompeng',
'Sundanese',
'Syloti_Nagri',
'Syriac',
'Tagalog',
'Tagbanwa',
'Tai_Le',
'Tai_Tham',
'Tai_Viet',
'Takri',
'Tamil',
'Telugu',
'Thaana',
'Thai',
'Tibetan',
'Tifinagh',
'Ugaritic',
'Vai',
'Yi'
);
$scriptTypes = array();
foreach(
$scriptNames as $n ) $scriptTypes[ $n ] = array();
for(
$i=0; $i <= 0x10fff; $i++ ) {
//echo $i.PHP_EOL;
foreach( $scriptNames as $scriptName ) {

if (
preg_match( '/[\p{'. $scriptName .'}]/u', mb_chr( $i, 'UTF-8') ) ) {

if (empty(
$scriptTypes[ $scriptName ])
|| ( (
$i - $scriptTypes[ $scriptName ][ count( $scriptTypes[ $scriptName ] ) - 1 ][1]) > 1)
) {

$scriptTypes[ $scriptName ][] = [$i, $i];

} else {

$scriptTypes[ $scriptName ][ count( $scriptTypes[ $scriptName ] ) - 1 ][1] = $i;
}
}
}
}
foreach(
$scriptTypes as $scriptName => $unicodeRanges ) {

printf(
'%s=[',
$scriptName
);
foreach(
$unicodeRanges as $r ) {

printf(
'\x{%04x}',
$r[0]
);
if (
$r[1] > $r[0] )
printf(
'-\x{%04x}',
$r[1]
);
}
printf(
']'.PHP_EOL
);
}
To Top