正規表現は、テキストを処理する強力な方法を提供します。正規表現を使用すると、ユーザー入力の複雑な検証を実行し、ユーザー入力とファイルの内容を解析し、文字列を再フォーマットすることができます。 PHP は、POSIX および PCRE 正規表現を簡単に使用する方法をユーザーに提供します。このチュートリアルでは、POSIX と PCRE の違いについて説明し、PHP V5 で正規表現を使用する方法を説明します。
始める前に
このチュートリアルから何が学べるか、そしてそれを最大限に活用する方法を学びましょう。
このチュートリアルについて
正規表現は、テキストを処理する強力な方法を提供します。正規表現を使用すると、ユーザー入力の複雑な検証を実行し、ユーザー入力とテキスト コンテンツを解析し、文字列を再フォーマットすることができます。
目標
このチュートリアルでは、POSIX および PCRE 正規表現を使用する簡単な方法に焦点を当て、PHP 正規表現に習熟できるようにします。 POSIX と PCRE の違いを調べ、PHP V5 で正規表現を使用する方法についても説明します。このチュートリアルに従うことで、正規表現をいつ、どのように使用するのか、そしてなぜ使用するのかを学びます。
システム要件
このチュートリアルは、PHP がインストールされている Microsoft® Windows® 系または UNIX® 系システム (Mac OS X および Linux® を含む) で完了できます。私たちが紹介するものはすべてPHP組み込みプラグインであるため、システムにPHPをインストールするだけで済み、他のソフトウェアをインストールする必要はありません。
スタート
正規表現とは何ですか?
数年前、私は Web フォームの入力フィールドの興味深いテストをいくつか行いました。ユーザーはこのフォームに電話番号を入力します。この電話番号は、ユーザーが入力したときに広告に印刷されます。必要に応じて、米国の電話番号は (555) 555-5555 または 555-555-5555 のいずれかの方法で入力できますが、555-5555 は受け入れられません。
なぜ数字以外の文字をすべて破棄して、残りの文字の合計数が 10 文字だけになるようにしたらよいのかと疑問に思われるかもしれません。この方法は機能しますが、ユーザーが !555?333-3333 などを入力することはできません。
ウェブ開発者の観点から見ると、この状況は興味深い課題を提示しています。さまざまな形式をチェックするルーチンを作成することもできますが、ユーザーが 555.555.5555 のような形式を受け入れる場合にある程度の柔軟性を持たせるソリューションを見つけたいと考えています。
これはまさに正規表現 (略して regex) が適しているものです。以前にそれらを切り取ってアプリに貼り付けましたが、理解できない構文の問題は一度も見つかりませんでした。正規表現は数式によく似ています。 2x2=4 という形式の式を見ると、通常、「2 x 2 = 4」と考えます。正規表現は非常によく似ています。この記事を読んだ後、次のような正規表現 ^b$ を見たとき、「行の先頭は b で、その後に行の末尾が続く」と自分に言い聞かせるでしょう。それだけでなく、PHP で正規表現を使用することがいかに簡単であるかがわかります。
正規表現を使用する場合
従うべきルールがある場合は、正規表現を使用して検索および置換操作を完了する必要がありますが、検索または置換する必要がある正確な文字を持っている必要はありません。たとえば、上記の電話番号の例では、ユーザーは、入力された電話番号の形式を示すルールを定義しますが、電話番号に含まれる数字は定義しません。これは、大量のユーザー入力があるシナリオにも当てはまります。米国の州の略称は、A から Z までの大文字 2 文字に制限されています。ここでは正規表現を使用することもでき、大文字と小文字や長さの問題に関係なく、フォーム内のテキストまたはユーザー入力をアルファベット文字に単純に制限できます。
正規表現を使用すべきではない場合
正規表現は強力ですが、いくつかの欠点もあります。そのうちの 1 つは、式を読み書きするスキルが必要です。アプリケーションに正規表現を含める場合は、正規表現を完全にコメント化する必要があります。こうすることで、後で他の人が式を変更する必要がある場合でも、機能を中断することなく変更できます。さらに、正規表現の使用に慣れていない場合、正規表現のデバッグが難しいと感じる可能性があります。
これらの問題を回避するには、より単純な組み込み関数で問題を十分に解決できる場合は、正規表現を使用しないでください。
POSIX と PCRE
PHP は、ポータブル オペレーティング システム実装 (POSIX) と Perl 互換正規表現 (PCRE) の 2 つの正規表現実装をサポートしています。 2 つの実装は異なる機能を提供しますが、PHP での使用は同様に簡単です。使用する正規表現スタイルは、正規表現のこれまでの経験と使用習慣によって異なります。 PCRE 式は POSIX 式よりわずかに高速であるという証拠がいくつかありますが、大部分のアプリケーションでは、この違いはそれほど重要ではありません。
この記事の例では、各正規表現メソッドの構文がコメントに含まれています。関数構文では、正規表現は regex
パラメーターであり、検索される文字列は string
です。括弧内のパラメータはオプションです。このチュートリアルでは主に基本的な内容を紹介するため、すべてのオプション パラメータを紹介するわけではありません。 regex
参数,所搜索的字符串为 string
。括号中的参数是可选的,由于本教程主要介绍基础内容,故不会给出全部可选参数的介绍。
正则表达式语法
尽管 POSIX 和 PCRE 实现在对某些特性和字符类的支持方面有所不同,但它们的语法是相同的。每个正则表达式都是由一个或多个字符、特殊字符(有时也称为元字符)、字符类和字符组构成的。
POSIX 和 PCRE 使用相同的通配符 —— 在 regex 中以通配符来表示 “此处可为任意内容”。通配符字符为一个英文句号或点(.
)。若要查找英文句号或点,可使用转义字符 /
: /.
。下文中所讨论的其他特殊字符也是如此,例如行锚(line anchor)和限定符。如果一个字符在正则表达式中有特殊含义,那么必须通过转义才能表达其原本的文字含义。
行锚 是特殊的元字符,与一行的开头和结尾相匹配,但不会捕获任何文本(参见表 1)。例如,如果某一行以字母 a
开头,那么表达式 ^a
中的行锚不会捕获字母 a
,而是匹配行的开头。
表 1. 行锚
限定符 应用于紧接于其前的表达式(参见表 2)。使用限定符,您可以指定在一次搜索中查找到一个表达式的次数。例如,表达式 a+
将一次或多次地查找到字母 a
。
表 2. 限定符
限定符 |
描述 |
? |
限定符之前的表达式可被查找到 0 次或 1 次 |
+ |
限定符之前的表达式可被查找到 1 次或多次 |
* |
限定符之前的表达式可被查找到任意次(含 0 次) |
{n} |
限定符之前的表达式仅可被查找到 n 次 |
{n,m} |
限定符之前的表达式可被查找到 n 次到 m 次之间 |
在 regex 中,捕获文本并在替换和搜索操作中引用该文本是一项非常有用的特性(参见表 3)。通过使用捕获功能,您可以执行搜索,来查找重复的单词和闭合的 HTML 及 XML 标记。如果您在替换时使用了捕获功能,那么可以将找回的文本置入替换字符串内。后面将给出一个示例,展示如何以超链接替换电子邮件地址。
表 3. 分组与捕获
🎜POSIX 実装と PCRE 実装は、特定の機能と文字クラスのサポートが異なりますが、構文は同じです。各正規表現は、1 つ以上の文字、特殊文字 (メタ文字と呼ばれることもあります)、文字クラス、および文字グループで構成されます。 🎜🎜POSIX と PCRE は同じワイルドカードを使用します。正規表現のワイルドカードは「ここにあるものはすべて」を意味します。ワイルドカード文字は、英語のピリオドまたはピリオド (
.
) です。英語のピリオドまたはドットを検索するには、エスケープ文字
/
:
/.
を使用します。行アンカーや修飾子など、以下で説明する他の特殊文字にも同じことが当てはまります。文字が正規表現内で特別な意味を持つ場合は、元の文字通りの意味を表現するためにエスケープする必要があります。 🎜🎜
行アンカーは、行の先頭と末尾に一致する特別なメタキャラクターですが、テキストはキャプチャされません (表 1 を参照)。たとえば、行が文字
a
で始まる場合、式
^a
の行アンカーは文字
a
をキャプチャせず、代わりにの行の先頭と一致します。 🎜🎜
表 1. 行アンカー🎜
アンカー |
説明 | 🎜
^ 🎜🎜行頭と一致します🎜🎜 |
$ 🎜 |
行末と一致しますline🎜🎜🎜 🎜🎜修飾子は、その直前の式に適用されます (表 2 を参照)。修飾子を使用すると、検索で式が見つかる回数を指定できます。たとえば、式 a+ では、文字 a が 1 回以上検出されます。 🎜🎜 表 2. 修飾子 🎜
修飾子 |
説明 | 🎜
? 🎜 🎜修飾子の前の式は 0 回または 1 回検索できます🎜🎜 |
+ 🎜🎜修飾子の前の式は 1 回以上検索できます🎜 🎜 |
* 🎜🎜修飾子前の式は何回でも検索可能(0回も含む)🎜🎜 |
{n} 🎜🎜修飾子の前の式は n 回しか見つかりません🎜🎜 |
{n, m} 🎜🎜修飾子の前の式は n 回から m 回の間で見つかります🎜🎜🎜🎜🎜 正規表現では、テキストをキャプチャし、置換して検索します。操作中にこのテキストを参照することは、非常に便利な機能です (表 3 を参照) )。キャプチャ機能を使用すると、検索を実行して、重複する単語や HTML および XML の終了タグを見つけることができます。置換時にキャプチャを使用すると、取得したテキストを置換文字列に配置できます。電子メール アドレスをハイパーリンクに置き換える例を後で示します。 🎜🎜 表 3. グループ化とキャプチャ 🎜
文字クラス |
説明 | 🎜
() 🎜🎜文字をグループ化し、テキストをキャプチャできるようにします🎜🎜🎜🎜POSIX 文字クラス
POSIX 正規表現は、多くの正規表現実装で使用できるようにするいくつかの標準に従っています (表 4 を参照)。たとえば、POSIX 正規表現を作成している場合、それを PHP で使用したり、grep コマンドで使用したり、正規表現をサポートする多くのエディタのいずれかで使用したりできます。 。 grep 命令使用它,也可以通过许多支持正则表达式的编辑器使用它。
表 4. POSIX 字符类
字符 |
描述 |
[:alpha:] |
匹配包含字母与数字的字符 |
[:digit:] |
匹配任意数字 |
[:space:] |
匹配任意空白 |
POSIX 匹配
有两个使用 POSIX 正则表达式搜索字符串的函数,即 ereg() 和 eregi() 。
ereg()
ereg() 方法为特定正则表达式搜索字符串。如果未找到任何匹配项,则返回 0,因此您可以给出如下测试:
清单 1. ereg() 方法
<?php
$phonenbr="555-555-5555";
// Syntax is ereg( regex, string [, out_captures_array])
if (ereg("[-[:digit:]]{12}", $phonenbr)) {
print("Found match!/n");
} else {
print("No match found!/n");
}
?> ログイン後にコピー |
正则表达式 [-[:digit:]]{12} 查找 12 个为数字或连字符的字符。就处理电话号码而言,这有些粗略,您也可将其改写成这样的形式:^[0-9]{3}-[0-9]{3}-[0-9]{4}$ 。(在 regex 中,[0-9] 和 [:digit:] 实际上是完全相同的,您可能更愿意使用 [0-9] 的形式,因为它更短些。)这种作为替代方案的表达式显然更为精确。它会查找行的开头(^ ),后接一组 3 个数字([0-9]{3} )、一个连字符(- )、另外一组 3 个数字、另外一个连字符、一组 4 个数字,然后是行的结尾($ )。当您手工编写表达式时,这会使您了解到正则表达式要处理的问题的复杂程度如何,从而有助于预测出使用表达式搜索或替换的数据类型。
eregi()
eregi() 方法类似于 ereg() ,不同之处在于它对大小写不敏感。它将返回一个包含所找到的匹配项长度的整数,但您很可能会将其用于条件语句中,如下所示:
清单 2. eregi() 方法
<?php
$str="Hello World!";
// Syntax is ereg( regex, string [, out_captures_array])
if (eregi("hello", $str)) {
print("Found match!/n");
} else {
print("No match found!/n");
}
?> ログイン後にコピー |
执行此示例时,将输出 Found match! ,这是因为在忽略大小写的搜索中找到了 hello。如果您使用的是 ereg ,搜索将失败。
POSIX 替换
ereg_replace() 和 eregi_replace() 这两种方法用于在文本中进行替换,具有 POSIX 正则表达式的特性。
ereg_replace()
您可以使用 ereg_replace() 方法以 POSIX 正则表达式语法进行大小写敏感的替换。如下示例描述了如何替换带有超链接的字符串内的电子邮件地址:
清单 3. ereg_replace() 方法
<?php
$origstr = "My e-mail address is: first.last@example.com";
// Syntax is: ereg_replace( regex, replacestr, string )
$newstr = /
ereg_replace("([.[:alpha:][:digit:]]+@[.[:alpha:][:digit:]]+)",
"<a href=/"mailto://1/">//1</a>", $origstr);
print("$newstr/n");
?> ログイン後にコピー |
这是一条用于匹配电子邮件地址的正则表达式的不完整版本,但它展示了与 str_replace() 等其他普通替换函数相比,ereg_replace() 的强大之处。在使用正则表达式时,您可定义搜索的规则,而不是搜索文字字符。
eregi_replace()
除忽略大小写之外,eregi_replace() 函数与 ereg_replace()
表 4. POSIX 文字クラス
Character |
説明 |
[:alpha:] |
文字と数字を含む文字と一致します |
[:digit:] |
は任意の数値と一致します🎜🎜
[:space:] 🎜 🎜任意の空白文字と一致します🎜🎜🎜🎜🎜🎜POSIX 一致🎜🎜 POSIX 関数を使用する正規表現が 2 つあります。文字列、つまり ereg() と eregi() を検索します。 🎜🎜🎜🎜ereg()🎜🎜🎜ereg() メソッドは、文字列から特定の正規表現を検索します。一致するものが見つからない場合は 0 が返されるので、次のようなテストを行うことができます: 🎜🎜🎜🎜🎜 リスト 1. ereg() メソッド 🎜🎜🎜🎜🎜🎜🎜<?php
$origstr = "1 BANANA, 2 banana, 3 Banana";
// Syntax is: eregi_replace( regex, replacestr, string )
$newstr = eregi_replace("banana", "pear", $origstr);
print("New string is: '$newstr'/n");
?> ログイン後にコピー 🎜🎜🎜🎜🎜🎜 正規表現 [-[:digit:]]{12} 数字またはハイフンである 12 文字を検索します。これは、電話番号の処理に関しては少し大雑把ですが、次のように書き換えることもできます: ^[0-9]{3}-[0-9]{3}-[0-9]{ 4 }$ 。 (正規表現では、[0-9] と [:digit:] は実際には同一です。[0-9] を使用することをお勧めします。この代替表現は明らかにより正確です。行の先頭 (^ )、その後に続く 3 つの数字のセット ([0-9]{3} )、ハイフン () を検索します。 - )、別の 3 桁のセット、別のハイフン、4 桁のセット、そして行末 ($ )。手動で式を作成すると、正規表現が処理しようとしている問題の複雑さがわかり、その式で検索または置換するデータの種類を予測するのに役立ちます。 🎜🎜🎜🎜eregi()🎜🎜🎜ereg() メソッドは、大文字と小文字を区別しないことを除いて、ereg() と似ています。これは、見つかった一致の長さを含む整数を返しますが、おそらく次のような条件ステートメントで使用することになります。 🎜🎜🎜この例を実行すると、大文字と小文字を無視した検索で hello が見つかったため、Found match! が出力されます。 ereg を使用している場合、検索は失敗します。 🎜🎜POSIX 置換🎜🎜ereg_replace() および eregi_replace( ) これら 2 つのメソッドはテキスト内の置換を実行するために使用され、POSIX 正規表現の特性を備えています。 🎜🎜🎜🎜ereg_replace()🎜🎜🎜 ereg_replace() メソッドを使用すると、POSIX 正規表現構文で大文字と小文字を区別した置換を実行できます。次の例は、文字列内の電子メール アドレスをハイパーリンクに置き換える方法を示しています。これは、電子メール アドレスを照合するための正規表現のバージョンですが、 ereg_replace() が str_replace() などの他の通常の置換関数と比較していかに強力であるかを示しています。正規表現を使用する場合は、リテラル文字を検索するのではなく、検索ルールを定義します。 🎜🎜🎜🎜eregi_replace()🎜🎜🎜 eregi_replace() 関数は、大文字小文字が無視されることを除いて ereg_replace() と同じです: 🎜🎜🎜🎜🎜リスト 4. eregi_replace () 関数🎜🎜🎜🎜🎜🎜🎜<?php
$array = array( "1", "3", "ABC", "XYZ", "42" );
// Syntax is preg_grep( regex, inputarray );
$grep_array = preg_grep("/^/d+$/", $array);
print_r($grep_array);
?> ログイン後にコピー ログイン後にコピー 🎜🎜🎜🎜 本例将 banana 替换为 pear ,替换操作忽略了大小写。PCRE 字符类
由于 PCRE 语法支持更短的字符类和更多的特性,因此它比 POSIX 语法更为强大。表 5 列出了 PCRE 中支持而在 POSIX 表达式中没有的部分字符类。
表 5. PCRE 字符类
字符类 |
描述 |
/b |
词边界,查找词的开始和结尾 |
/d |
匹配任意数字 |
/s |
匹配任意空白,如 tab 或空格 |
/t |
匹配一个 tab 字符 |
/w |
匹配包含字母与数字的字符 |
PCRE 匹配
PHP 中的 PCRE 匹配函数与 POSIX 匹配函数类似,但如果您习惯使用 POSIX 表达式,那么 PCRE 匹配函数的一项特性可能会使您感到棘手:PCRE 函数要求表达式以分隔符开始和结束。在绝大多数示例中,分隔符都是一个 / ,可在引号内表达式的开始和结尾处看到。务必牢记,此分隔符并非表达式的一部分。
在 PCRE 中的最后一个分隔符后,您可添加一个修饰符来更改正则表达式的行为。举例来说,i 修饰符使正则表达式对大小写不敏感。这是与 POSIX 方法的一项重要差异,在 POSIX 中,您需要按照对大小写敏感性的需求来调用不同的方法。
preg_grep()
preg_grep() 方法返回一个数组,其中包含通过正则表达式在其中找到匹配项的另外一个数组的全部项目。如果您有一个较大的值集,并希望对其进行搜索以查找匹配项,那么该方法非常有用。下面是一个示例:
清单 5. preg_grep() 方法
<?php
$array = array( "1", "3", "ABC", "XYZ", "42" );
// Syntax is preg_grep( regex, inputarray );
$grep_array = preg_grep("/^/d+$/", $array);
print_r($grep_array);
?> ログイン後にコピー ログイン後にコピー |
在本例中,正则表达式 ^/d+$ 查找行的开始(^ )和结尾($ )之间包含一个或多个数字(/d+ )的数组的所有元素。
preg_match()
preg_match() 函数使用 PCRE 在字符串中查找匹配项,它需要两个参数:regex 和字符串。您可以选择提供一个将由匹配项填充的数组、允许您修改匹配操作行为的标志,还可提供字符串中开始查找匹配项的位置(offset )。示例如下:
清单 6. offset 方法
<?php
$string = "abcdefgh";
$regex = "/^[a-z]+$/i";
// Syntax is preg_match(regex, string, [, out_matches [, flags [, offset]]]);
if (preg_match($regex, $string)) {
printf("Pattern '%s' found in string '%s'/n", $regex, $string);
} else {
printf("No match found in string '%s'!/n", $string);
}
?> ログイン後にコピー |
本例使用了正则表达式 ^[a-z]+$ ,在行的开始(^ )和结尾($ )之间搜索可查找到一次或多次的([a-z]+ )、从 a 到 z 的任意字母。
preg_match_all()
preg_match_all() 函数为在字符串中查找到的全部匹配项构建一个数组。下例构建了一个包含句子中全部词的数组:
清单 7. preg_match_all() 函数
<?php
$string = "The quick red fox jumped over the lazy brown dog";
$re = "//b/w+/b/";
// Syntax is preg_match_all( regex, string, return_array [, flags [, offset]])
preg_match_all($re, $string, $arrayout);
print_r($arrayout);
?> ログイン後にコピー |
正则表达式 /b/w+/b 在词边界(/b )间查找可找到一次或多次的(/w+ )单词字符。每个词都将置入输出数组 $arrayout 的一个数组元素中。
PCRE 替换
在 PHP 中进行 PCRE 替换与 POSIX 替换类似,不同之处在于使用的是 preg_replace() 而非 ereg_replace() 和 eregi_replace() 。
preg_replace()
preg_replace() 函数使用 PCRE 进行替换。它需要这样几个参数:正则表达式、替换表达式和原始字符串。您还可以选择提供希望的最大替换数,以及以所完成的替换数填充的变量。示例如下:
清单 8. preg_replace() 函数
<?php
$orig_string = "5555555555";
printf("Original string is '%s'/n", $orig_string);
$re = "/^(/d{3})(/d{3})(/d{4})$/";
// Syntax is preg_replace( regex, replacement, string /
[, limit [, out_count]] );
$new_string = preg_replace($re, "(//1) //2-//3", $orig_string);
printf("New string is '%s'/n", $new_string);
?> ログイン後にコピー |
この例では、テキストの一部をキャプチャし、//1 などの後方参照を使用する方法を簡単に示します。これらの後方参照は、括弧内で一致するテキストに挿入されます。この場合、//1 はグループ 1、(/d{3}) と一致します。 //1 。这些反向引用会插入圆括号内所匹配的任意文本中,在本例中,//1 匹配第 1 组 (/d{3}) 。
在示例中,您可使用 substr 将电话号码分割开来,而对字符串只需进行少量更改,要依靠 substr 来可靠地捕获正确文本会更加困难。
如果字符串的形式可为 (555)5555555 ,您可将表达式修改为 ^(?(/d{3}))?(/d{3})(/d{4})$ この例では、substr を使用して文字列を少し変更するだけで電話番号を分割し、substr に依存して正しいテキストを確実にキャプチャできます。より困難。 文字列が (555)5555555 の形式である場合は、式を ^(?(/d{3}))?(/d{3} に変更できます。 ) (/d{4})$ を使用してかっこを見つけます。 結論
PHP には、正規表現用の 2 つの構文、POSIX と PCRE が用意されています。このチュートリアルでは、POSIX および PCRE 正規表現をサポートする PHP の主な関数の概要を説明します。 正規表現を使用すると、テキストの検索と置換をはるかに超えた、より強力な検索と置換の操作を実行するルールを定義できます。 参考資料
学習
-
この記事の 英語原文 は、developerWorks グローバル サイトで参照できます。
-
Regular-Expressions.info は、正規表現に関する関連情報を提供します。
-
PHP: 正規表現関数 (Perl 互換) - Manual は、PCRE 関連のコンテンツをカバーする PHP オンライン ドキュメントです。
-
正規表現関数 (POSIX 拡張) は、POSIX に関する PHP オンライン ドキュメントです。
-
PHP の詳細については、developerWorks の PHP プロジェクト リソース にアクセスしてください。
-
PHP でのプログラミングの学習に関する developerWorks チュートリアルについては、「PHP を学ぶ、パート 1」、パート 2 、および パート 3 を参照してください。
-
最新の developerWorks 技術イベントと Web キャストについて学びましょう 。
-
developerWorks の オープンソース ゾーン にアクセスして、オープン ソース テクノロジーを使用した開発や IBM 製品での使用に役立つ広範なハウツー情報、ツール、プロジェクトの最新情報を入手してください。
PHP.net- から製品とテクノロジーを入手
PHPの最新バージョン をダウンロードしてください。
正規表現ライブラリ には、正規表現の大規模なリポジトリがあります。
無料の Linux SEK を注文してください 。これには、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® など、Linux プラットフォーム上の IBM の最新試用版ソフトウェアが含まれる 2 枚の DVD が含まれています。
-
ダウンロードまたは DVD で入手できる IBM 試用版ソフトウェア を使用して、次のオープンソース プロジェクトを革新しましょう。
ディスカッション
-
developerWorks ブログ に参加して、developerWorks コミュニティに参加してください。
著者について
|
|
|
ネイサン・A・グッドはミネソタ州ツインシティーズのライターです、ソフトウェア エンジニア、システム管理者。彼の著書には、Lee Babin らとの共著『PHP 5 Recipes: A 問題解決アプローチ』 (Apress、2005 年)、『Windows 開発者のための正規表現レシピ: A 問題解決アプローチ』 (Apress、2005 年) などがあります。 Apress Press、2005 年)、Kapil Sharma らとの共著、正規表現: 問題解決アプローチ (Apress Press、2005 年)、およびProfessional Red Hat Enterprise Linux 3 (Wrox Press、2004 年)。 |
🎜 |
|
|
|