PHP 8.2.0 Beta 3 available for testing

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 9 notes

up
16
huhwatnouDONTspamPLEASE at hotmail dot com
6 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
8
mercury at caucasus dot net
12 years ago
An excellent article explaining all these properties can be found here: http://www.regular-expressions.info/unicode.html
up
10
xuantoaiph at gmail dot com
8 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
4
o_shes01 at uni-muenster dot de
11 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
4
suit at rebell dot at
12 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
phpnet at N_O_S_P_A_M dot osps dot net
3 days 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
   
);
}
up
0
Yzmir Ramirez
8 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
-1
php at lnx-bsp dot net
4 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
-4
o_shes01 at uni-muenster dot de
11 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
To Top