PHP Conference Japan 2024

preg_match

(PHP 4, PHP 5, PHP 7, PHP 8)

preg_match執行正規表示式比對

描述

preg_match(
    string $pattern,
    string $subject,
    array &$matches = null,
    int $flags = 0,
    int $offset = 0
): int|false

subject 中搜尋符合 pattern 中給定的正規表示式之匹配項。

參數

pattern

要搜尋的模式,為字串。

subject

輸入字串。

matches

如果提供 matches,則會以搜尋結果填入。 $matches[0] 將包含符合完整模式的文字,$matches[1] 將包含符合第一個捕獲的帶括號的子模式的文字,依此類推。

flags

flags 可以是以下旗標的組合

PREG_OFFSET_CAPTURE

如果傳遞此旗標,則對於每次出現的匹配,也會返回附加的字串偏移量(以位元組為單位)。請注意,這會將 matches 的值變更為陣列,其中每個元素都是一個陣列,該陣列由偏移量為 0 的匹配字串及其在 subject 中偏移量為 1 的字串偏移量組成。

<?php
preg_match
('/(foo)(bar)(baz)/', 'foobarbaz', $matches, PREG_OFFSET_CAPTURE);
print_r($matches);
?>

上述範例將輸出

Array
(
    [0] => Array
        (
            [0] => foobarbaz
            [1] => 0
        )

    [1] => Array
        (
            [0] => foo
            [1] => 0
        )

    [2] => Array
        (
            [0] => bar
            [1] => 3
        )

    [3] => Array
        (
            [0] => baz
            [1] => 6
        )

)

PREG_UNMATCHED_AS_NULL

如果傳遞此旗標,則未匹配的子模式會回報為 null;否則,它們會回報為空的 string

<?php
preg_match
('/(a)(b)*(c)/', 'ac', $matches);
var_dump($matches);
preg_match('/(a)(b)*(c)/', 'ac', $matches, PREG_UNMATCHED_AS_NULL);
var_dump($matches);
?>

上述範例將輸出

array(4) {
  [0]=>
  string(2) "ac"
  [1]=>
  string(1) "a"
  [2]=>
  string(0) ""
  [3]=>
  string(1) "c"
}
array(4) {
  [0]=>
  string(2) "ac"
  [1]=>
  string(1) "a"
  [2]=>
  NULL
  [3]=>
  string(1) "c"
}

offset

一般來說,搜尋從主體字串的開頭開始。選用參數 offset 可用於指定開始搜尋的替代位置(以位元組為單位)。

注意:

使用 offset 不等同於將 substr($subject, $offset) 傳遞給 preg_match() 來代替主體字串,因為 pattern 可以包含斷言,例如 ^$(?<=x)。比較

<?php
$subject
= "abcdef";
$pattern = '/^def/';
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3);
print_r($matches);
?>

上述範例將輸出

Array
(
)

而此範例

<?php
$subject
= "abcdef";
$pattern = '/^def/';
preg_match($pattern, substr($subject,3), $matches, PREG_OFFSET_CAPTURE);
print_r($matches);
?>

將產生

Array
(
    [0] => Array
        (
            [0] => def
            [1] => 0
        )

)

或者,為了避免使用 substr(),請使用 \G 斷言,而非 ^ 定位符,或改用 A 修飾符,兩者都與 offset 參數搭配使用。

回傳值

如果 pattern 符合給定的 subjectpreg_match() 會回傳 1;如果沒有符合,則回傳 0;如果失敗,則回傳 false

警告

此函式可能會回傳布林值 false,但也可能會回傳評估為 false 的非布林值。請閱讀關於 布林值 的章節,以取得更多資訊。使用 === 運算子來測試此函式的回傳值。

錯誤/例外

如果傳遞的正規表示式模式無法編譯為有效的正規表示式,則會發出 E_WARNING

更新紀錄

版本 描述
7.2.0 現在 $flags 參數支援 PREG_UNMATCHED_AS_NULL

範例

範例 1 尋找文字字串「php」

<?php
// 模式分隔符號後的 "i" 表示不區分大小寫的搜尋
if (preg_match("/php/i", "PHP is the web scripting language of choice.")) {
echo
"找到匹配項。";
} else {
echo
"未找到匹配項。";
}
?>

範例 2 尋找單字「web」

<?php
/* 模式中的 \b 表示單字邊界,因此只會匹配不同的
* 單字「web」,而不會匹配「webbing」或「cobweb」等部分單字 */
if (preg_match("/\bweb\b/i", "PHP is the web scripting language of choice.")) {
echo
"找到匹配項。";
} else {
echo
"未找到匹配項。";
}

if (
preg_match("/\bweb\b/i", "PHP is the website scripting language of choice.")) {
echo
"找到匹配項。";
} else {
echo
"未找到匹配項。";
}
?>

範例 3 從 URL 中取得網域名稱

<?php
// 從 URL 取得主機名稱
preg_match('@^(?:http://)?([^/]+)@i',
"https://php.dev.org.tw/index.html", $matches);
$host = $matches[1];

// 取得主機名稱的最後兩個區段
preg_match('/[^.]+\.[^.]+$/', $host, $matches);
echo
"網域名稱是: {$matches[0]}\n";
?>

上述範例將輸出

domain name is: php.net

範例 #4 使用具名子模式

<?php

$str
= 'foobar: 2008';

preg_match('/(?P<name>\w+): (?P<digit>\d+)/', $str, $matches);

/* 替代方案 */
// preg_match('/(?<name>\w+): (?<digit>\d+)/', $str, $matches);

print_r($matches);

?>

上述範例將輸出

Array
(
    [0] => foobar: 2008
    [name] => foobar
    [1] => foobar
    [digit] => 2008
    [2] => 2008
)

注意事項

提示

如果您只是想檢查一個字串是否包含在另一個字串中,請不要使用 preg_match()。請改用 strpos(),因為它會更快。

參見

新增筆記

使用者貢獻的筆記 51 則筆記

force at md-t dot org
13 年前
簡單的正規表示式

正規表示式快速參考
[abc] 單一字元:a、b 或 c
[^abc] 除了 a、b 或 c 之外的任何單一字元
[a-z] a-z 範圍內的任何單一字元
[a-zA-Z] a-z 或 A-Z 範圍內的任何單一字元
^ 行首
$ 行尾
\A 字串開頭
\z 字串結尾
. 任何單一字元
\s 任何空白字元
\S 任何非空白字元
\d 任何數字
\D 任何非數字
\w 任何單字字元 (字母、數字、底線)
\W 任何非單字字元
\b 任何單字邊界字元
(...) 擷取所有括號內的內容
(a|b) a 或 b
a? 零或一個 a
a* 零或多個 a
a+ 一或多個 a
a{3} 恰好 3 個 a
a{3,} 3 個或更多個 a
a{3,6} 3 到 6 個 a

選項:i 大小寫不敏感 m 使點號匹配換行符號 x 忽略正規表示式中的空白 o 只執行一次 #{...} 替換
yofilter-php at yahoo dot co dot uk
11 年前
似乎沒有任何提及可以在正規表示式中使用的 PHP 版本切換。

preg_match_all('/正規表示式/sim',$text)。

s i m 是可用切換的位置 (我所知道的)。
i 是忽略字母大小寫 (這通常是已知的 - 我認為)。
s 告訴程式碼當遇到 \n (換行符號) 時不要停止搜尋 - 這對於例如需要搜尋的編輯器中的多行輸入文字很重要。
m 告訴程式碼它是一個多行輸入,但重要的是允許在使用 ^ 和 $ 時顯示開始和結束。

我希望這能讓某人從我忍受的 4 小時折磨中解脫出來,試圖解決這個問題。
MrBull
13 年前
有時候,否定字串很有用。首先想到的方法是:[^(字串)],但這當然行不通。有一個解決方案,但它並不廣為人知。以下是如何否定字串的簡單程式碼片段

(?:(?!字串).)

?: 產生一個子模式 (請參閱 https://php.dev.org.tw/manual/en/regexp.reference.subpatterns.php),而 ?! 是一個負向先行斷言。您將負向先行斷言放在點號前面,因為您希望正規表示式引擎首先檢查是否有您要否定的字串出現。只有當它不存在時,您才要匹配任意字元。

希望這對某些人有幫助。
cebelab at gmail dot com
14 年前
我注意到為了處理 UTF-8 文字,而無需重新編譯啟用 PCRE UTF-8 旗標的 php,您只需在模式開頭新增以下序列:(*UTF8)

例如:'#(*UTF8)[[:alnum:]]#' 對於 'é' 將傳回 TRUE,而 '#[[:alnum:]]#' 將傳回 FALSE

在直接在 pcre 網站上研究了數小時後,在這裡找到了這個非常有用的提示:http://www.pcre.org/pcre.txt
該函式庫中還有許多關於 UTF-8 支援的資訊

希望這會有幫助!

--
cedric
ruakuu at NOSPAM dot com
15 年前
正在開發一個需要日文和英文字母的網站,並且需要
使用 preg_match 驗證輸入,我嘗試使用 \p{script} 但沒有用

<?php
$pattern
='/^([-a-zA-Z0-9_\p{Katakana}\p{Hiragana}\p{Han}]*)$/u'; // 無效
?>

所以我嘗試使用範圍,它有效

<?php
$pattern
='/^[-a-zA-Z0-9_\x{30A0}-\x{30FF}'
.'\x{3040}-\x{309F}\x{4E00}-\x{9FBF}\s]*$/u';
$match_string = '印刷最安 ニキビ跡除去 ゲームボーイ';

if (
preg_match($pattern, $match_string)) {
echo
"找到 - 模式 $pattern";
} else {
echo
"未找到 - 模式 $pattern";
}
?>

U+4E00–U+9FBF 漢字
U+3040–U+309F 平假名
U+30A0–U+30FF 片假名

希望它有用,我花了幾個小時才弄清楚。
matt at proweb dot co dot uk
3 年前
pcre2-移轉

狀態:已實作 (在 PHP 7.3 中)

SELinux 會阻止 PREG_* 函式運作

2 月 8 日 12:40:51 伺服器名稱 setroubleshoot:SELinux 正在阻止 httpd 在程序上使用 execmem 存取。

您需要將 preg.jit=0 新增至 php.ini 或 init_set('preg.jit', 0) 如果您無法執行此操作

嘗試 [PCRE] 區段,以便您可以找到它
mohammad40g at gmail dot com
13 年前
此範例用於檢查波斯文字符

<?php
preg_match
("/[\x{0600}-\x{06FF}\x]{1,32}/u", 'محمد');
?>
asdfasdasad34535 at iflow dot at
11 年前
注意!當使用 u 修飾符時,PREG_OFFSET_CAPTURE 不會感知 UTF-8
這不是錯誤,而是一個功能
https://bugs.php.net/bug.php?id=37391

可能的解決方法:使用 mb_strpos 取得正確的偏移量,而不是使用旗標。

如果能支援 UTF-8 就太好了。
workhorse at op dot pl
13 年前
嘗試使用回車符號 (/n/r) 驗證 $subject 時,Preg_match 會傳回空結果。
要解決這個問題,需要在 $pattern 字串中使用 /s 修飾符。
<?php
$pattern
='/.*/s';
$valid=preg_match($pattern, $subject, $match);
?>
arash dot hemmat at gmail dot com
13 年前
給那些正在搜尋使用 preg_match 的 Unicode 正規表達式範例的人,這裡有一個例子:

檢查波斯數字
preg_match( "/[^\x{06F0}-\x{06F9}\x]+/u" , '۱۲۳۴۵۶۷۸۹۰' );
luc _ santeramo at t yahoo dot com
15 年前
如果你想用一行程式碼驗證電子郵件,請使用 filter_var() 函數!
http://fr.php.net/manual/en/function.filter-var.php

使用方式簡單,如同文件中範例所述
var_dump(filter_var('bob@example.com', FILTER_VALIDATE_EMAIL));
jonathan dot lydall at gmail dot removethispart dot com
16 年前
因為撰寫一個真正正確的電子郵件驗證函數比想像中困難,請考慮使用 PHP 內建的 filter_var 函數 (https://php.dev.org.tw/manual/en/function.filter-var.php)

<?php
$email
= "someone@domain .local";

if(!
filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo
"電子郵件無效";
} else {
echo
"電子郵件有效";
}
?>
splattermania at freenet dot de
15 年前
因為我浪費了很多時間尋找一個真正的 URL 正規表達式,最後還是自己建立了一個,現在我找到一個似乎適用於所有種類 URL 的正規表達式:

<?php
$regex
= "((https?|ftp)\:\/\/)?"; // SCHEME (協定)
$regex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?"; // User and Pass (使用者和密碼)
$regex .= "([a-z0-9-.]*)\.([a-z]{2,3})"; // Host or IP (主機或 IP)
$regex .= "(\:[0-9]{2,5})?"; // Port (埠號)
$regex .= "(\/([a-z0-9+\$_-]\.?)+)*\/?"; // Path (路徑)
$regex .= "(\?[a-z+&\$_.-][a-z0-9;:@&%=+\/\$_.-]*)?"; // GET Query (GET 查詢)
$regex .= "(#[a-z_.-][a-z0-9+\$_.-]*)?"; // Anchor (錨點)
?>

然後,檢查正規表達式的正確方法如下:

<?php
if(preg_match("/^$regex$/", $url))
{
return
true;
}
?>
ulli dot luftpumpe at murkymind dot de
12 年前
匹配反斜線字元可能會令人困惑,因為在模式中需要雙重跳脫:首先是針對 PHP,其次是針對正規表達式引擎。
<?php
//匹配換行控制字元:
preg_match('/\n/','\n'); //模式匹配,並以控制字元 0x0A 儲存在模式字串中
preg_match('/\\\n/','\n'); //相同的匹配,但以跳脫字元 0x5C,0x6E 儲存在模式字串中

//嘗試在文字檔中匹配 "\'"(2 個字元),在 PHP 字串中為 '\\\'':
$subject = file_get_contents('myfile.txt');
preg_match('/\\\'/',$subject); //不匹配!!! 儲存為 0x5C,0x27 (跳脫的單引號),這只會匹配單引號
preg_match('/\\\\\'/',$subject); //匹配,儲存為 0x5C,0x5C,0x27 (跳脫的反斜線和未跳脫的單引號)
preg_match('/\\\\\\\/',$subject); //也匹配,儲存為 0x5C,0x5C,0x5C,0x27 (跳脫的反斜線和跳脫的單引號)

//匹配 "\n"(2 個字元):
preg_match('/\\\\n/','\\n');
preg_match('/\\\n/','\\n'); //相同的匹配 - 如果後面的字元不可跳脫,則 3 個反斜線在 PHP 中會被解釋為 2 個
?>
daevid at daevid dot com
15 年前
我今天剛從一位 Python 朋友那裡學到命名群組,並且好奇 PHP 是否支援它們,猜猜看 -- 它支援!!!

https://regular-expressions.dev.org.tw/named.html

<?php
preg_match
("/(?P<foo>abc)(.*)(?P<bar>xyz)/",
'abcdefghijklmnopqrstuvwxyz',
$matches);
print_r($matches);
?>

將產生

陣列
(
[0] => abcdefghijklmnopqrstuvwxyz
[foo] => abc
[1] => abc
[2] => defghijklmnopqrstuvw
[bar] => xyz
[3] => xyz
)

請注意,您實際上會取得命名群組以及數值索引鍵
的值,因此如果您使用它們,並且您正在計算陣列元素,請注意
您的陣列可能會比您最初預期的要大。
SoN9ne at gmail dot com
14 年前
我一直在開發一個電子郵件系統,該系統將使用 strip_tags() 自動從給定的 HTML 電子郵件產生文字電子郵件。
就我的需求而言,我遇到的唯一問題是連結會無法保留。
我搜尋了一段時間,但找不到任何可以從標籤中移除連結的東西,所以我產生了自己的小程式碼片段。
我將其張貼在這裡,希望其他人可能會覺得它有用,並供日後參考。

請記住一件事
我主要關注的是有效的 HTML,因此如果屬性沒有使用 ' 或 " 來包含值,則需要對此進行調整。
如果您可以編輯此程式碼以使其更好地工作,請告訴我。
<?php
/**
* 將錨點標籤替換為文字
* - 將搜尋字串並將所有錨點標籤替換為文字 (不區分大小寫)
*
* 運作方式:
* - 在字串中搜尋錨點標籤,檢查是否符合條件
* 錨點搜尋條件:
* - 1 - <a (必須有錨點標籤的開頭)
* - 2 - 在 href 屬性前後可以有任意數量的空格或其他屬性
* - 3 - 必須關閉錨點標籤
*
* - 一旦通過檢查,它將使用字串替換來替換錨點標籤
* - 字串替換可以自訂
*
* 已知問題:
* - 這不適用於未使用 ' 或 " 來包含屬性的錨點。
* (例如 - <a href=http: //php.dev.org.tw>PHP.net</a> 將不會被替換)
*/
function replaceAnchorsWithText($data) {
/**
* 必須修改 $regex,使其可以發佈到網站上...所以我將其分成 6 個部分。
*/
$regex = '/(<a\s*'; // 錨點標籤的開頭
$regex .= '(.*?)\s*'; // 可能存在或不存在的任何屬性或空格
$regex .= 'href=[\'"]+?\s*(?P<link>\S+)\s*[\'"]+?'; // 抓取連結
$regex .= '\s*(.*?)\s*>\s*'; // 在關閉標籤之前可能存在或不存在的任何屬性或空格
$regex .= '(?P<name>\S+)'; // 抓取名稱
$regex .= '\s*<\/a>)/i'; // 關閉錨點標籤之間的任意數量空格 (不區分大小寫)

if (is_array($data)) {
// 這將替換連結 (根據您的喜好修改)
$data = "{$data['name']}({$data['link']})";
}
return
preg_replace_callback($regex, 'replaceAnchorsWithText', $data);
}

$input = 'Test 1: <a href="http: //php.dev.org.tw1">PHP.NET1</a>.<br />';
$input .= 'Test 2: <A name="test" HREF=\'HTTP: //PHP.NET2\' target="_blank">PHP.NET2</A>.<BR />';
$input .= 'Test 3: <a hRef=http: //php.dev.org.tw3>php.net3</a><br />';
$input .= 'This last line had nothing to do with any of this';

echo
replaceAnchorsWithText($input).'<hr/>';
?>
將輸出
測試 1: PHP.NET1(http: //php.dev.org.tw1)。
測試 2: PHP.NET2(HTTP: //PHP.NET2)。
測試 3: php.net3 (仍然是一個錨點)
最後一行與此無關

發佈到此網站很痛苦...
必須分解 regex,並且必須中斷測試連結,因為它被標記為垃圾郵件...
Jonny 5
12 年前
在 UTF-8 中取得偏移量的解決方法
(在某些情況下,mb_strpos 也可能是一個選項)

<?php
if(preg_match($pattern,$haystack,$out,PREG_OFFSET_CAPTURE)) {
$offset = strlen(utf8_decode(substr($haystack,0,$out[0][1])));
}
?>
danielrydell at gmail dot com
7 年前
當嘗試匹配帶重音的字元時,例如西班牙語中的字元,當使用字元類別時,似乎有不同的內部解釋。因此,最好的方法是在分隔符後添加 u 選項 (表示 unicode)。

<?php

// 輸出 1 (添加 u 不會改變結果)
echo preg_match('/^áéíóúñ$/', 'áéíóúñ');

// 輸出 0 (除非使用 [ó]+ 或 [ó]* 或添加 u)
echo preg_match('/^áéí[ó]úñ$/', 'áéíóúñ');

// 所以要匹配 'espana' 或 'españa',添加 u,否則這不會匹配
// 輸出 1
echo preg_match('/^espa[nñ]a$/u', 'españa');

?>
chat dot noir at arcor dot de
7 年前
請注意,如果沒有匹配到帶括號的群組,則其鍵可能存在也可能不存在於 $matches 中。例如,

<?php preg_match('/(foo)?(bar)?(baz)?/', 'bar', $matches);
print_r($matches);

// 輸出
// 陣列
// (
// [0] => bar
// [1] =>
// [2] => bar
// )
?>
請注意,$matches 中沒有鍵為 '3' 的元素,但有一個鍵為 '1' 的元素 (空字串)。這種不一致的行為也適用於命名的群組。
Nimja
12 年前
當使用「不良詞語拒絕字串」篩選器時,preg_match 比 strpos / stripos 快得多。因為在其他情況下,您需要為每個單字執行 foreach。透過有效率的程式設計,只有在找到禁詞列表中的第一個單字時,foreach 才會更快。

(對於 12 個單字,100,000 次迭代,沒有找到單字)
stripos - 花費 1.4876 秒。
strpos - 花費 1.4207 秒。
preg_match - 花費 0.189 秒。

有趣的事實
對於長單字 ('averylongwordtospitepreg'),差異僅小得多。只有大約 2/3 的時間,而不是 1/6

<?php

$words
= array('word1', 'word2', 'word3', 'word4', 'word5', 'word6', 'word7', 'word8', 'word9', 'word10', 'word11', 'word12' );
$teststring = 'ThIs Is A tEsTsTrInG fOr TeStInG.';
$count = 100000;
$find = 0;

$start = microtime(TRUE);
for (
$i = 0; $i < $count; $i++) {
foreach (
$words as $word) {
if (
stripos($teststring, $word) !== FALSE) {
$find++;
break;
}
}
}
echo
'stripos - 耗時 ' . round(microtime(TRUE) - $start, 4) . ' 秒。' . PHP_EOL;

$start = microtime(TRUE);
for (
$i = 0; $i < $count; $i++) {
foreach (
$words as $word) {
if (
strpos($teststring, $word) !== FALSE) {
$find++;
break;
}
}
}
echo
'strpos - 耗時 ' . round(microtime(TRUE) - $start, 4) . ' 秒。' . PHP_EOL;

$start = microtime(TRUE);
$pattern = '/';
$div = '';
foreach (
$words as $word) {
$pattern .= $div . preg_quote($word);
$div = '|';
}
$pattern .= '/i';
//如果單字是靜態的,則模式可以輕鬆地在其他地方完成。
for ($i = 0; $i < $count; $i++) {
if (
preg_match($pattern, $teststring)) {
$find++;
}
}
$end = microtime(TRUE);
echo
'preg_match - 耗時 ' . round($end - $start, 4) . ' 秒。' . PHP_EOL;
?>
sainnr at gmail dot com
13 年前
如果您正在處理資料庫欄位類型,這個範例正規表示式可能會很有用。

(?P<type>\w+)($|\((?P<length>(\d+|(.*)))\))

例如,如果您有像 "varchar(255)" 或 "text" 這樣的類型,那麼接下來的程式碼片段

<?php
$type
= 'varchar(255)'; // 欄位類型
preg_match('/(?P<type>\w+)($|\((?P<length>(\d+|(.*)))\))/', $type, $field);
print_r($field);
?>

將會輸出類似以下的結果
Array ( [0] => varchar(255) [type] => varchar [1] => varchar [2] => (255) [length] => 255 [3] => 255 [4] => 255 )
ian_channing at hotmail dot com
13 年前
當嘗試檢查可能是 Windows 或 Unix 的檔案路徑時,我嘗試了好幾次才正確使用跳脫字元。

Unix 目錄分隔符號必須跳脫一次,而 Windows 目錄分隔符號必須跳脫兩次。

這會匹配 path/to/file 和 path\to\file.exe

preg_match('/^[a-z0-9_.\/\\\]*$/i', $file_string);
andre at koethur dot de
11 年前
請注意使用子模式時的錯誤 https://bugs.php.net/bug.php?id=50887:結尾未匹配的可選子模式不會顯示在 $matches 中。

這是一個解決方法:為您感興趣的所有子模式指定一個名稱,然後將 $match 與包含一些合理預設值的常數陣列合併。

<?php
if (preg_match('/^(?P<lang>[^;*][^;]*){1}(?:;q=(?P<qval>[0-9.]+))?$/u', 'de', $match))
{
$match = array_merge(array('lang' => '', 'qval' => ''), $match);
print_r($match);
}
?>

這會輸出
陣列
(
[lang] => de
[qval] =>
[0] => de
[1] => de
)

而不是
陣列
(
[0] => de
[lang] => de
[1] => de
)
Yousef Ismaeil Cliprz
11 年前
有時駭客會使用 PHP 檔案或 Shell 作為圖片來駭入您的網站。因此,如果您嘗試使用範例中的 move_uploaded_file() 函數來允許使用者上傳檔案,您必須檢查此檔案是否包含惡意程式碼,因此我們使用此函數 preg_match。

在此函數中我們使用

unlink() - https://php.dev.org.tw/unlink

在您上傳檔案後,使用以下函數檢查檔案。

<?php

/**
* 一個簡單的函數來檢查檔案是否有惡意程式碼。
*
* @param (string) $file - 檔案路徑。
* @author Yousef Ismaeil - Cliprz[at]gmail[dot]com。
*/
function is_clean_file ($file)
{
if (
file_exists($file))
{
$contents = file_get_contents($file);
}
else
{
exit(
$file." 不存在。");
}

if (
preg_match('/(base64_|eval|system|shell_|exec|php_)/i',$contents))
{
return
true;
}
else if (
preg_match("#&\#x([0-9a-f]+);#i", $contents))
{
return
true;
}
elseif (
preg_match('#&\#([0-9]+);#i', $contents))
{
return
true;
}
elseif (
preg_match("#([a-z]*)=([\`\'\"]*)script:#iU", $contents))
{
return
true;
}
elseif (
preg_match("#([a-z]*)=([\`\'\"]*)javascript:#iU", $contents))
{
return
true;
}
elseif (
preg_match("#([a-z]*)=([\'\"]*)vbscript:#iU", $contents))
{
return
true;
}
elseif (
preg_match("#(<[^>]+)style=([\`\'\"]*).*expression\([^>]*>#iU", $contents))
{
return
true;
}
elseif (
preg_match("#(<[^>]+)style=([\`\'\"]*).*behaviour\([^>]*>#iU", $contents))
{
return
true;
}
elseif (
preg_match("#</*(applet|link|style|script|iframe|frame|frameset|html|body|title|div|p|form)[^>]*>#i", $contents))
{
return
true;
}
else
{
return
false;
}
}
?>

使用方法

<?php
// 如果圖片包含惡意程式碼
$image = "simpleimage.png";

if (
is_clean_file($image))
{
echo
"惡意程式碼,這不是圖片";
unlink($image);
}
else
{
echo
"這是真正的圖片。";
}
?>
ian_channing at hotmail dot com
15 年前
這是一個使用正規表示式來比對整個歐盟所需各種增值稅格式的函數。

<?php
/**
* @param integer $country 國家名稱
* @param integer $vat_number 要測試的增值稅號碼,例如 GB123 4567 89
* @return integer -1 如果國家未包含,或 1 如果增值稅號碼與國家匹配,或 0 如果不匹配
*/
function checkVatNumber( $country, $vat_number ) {
switch(
$country) {
case
'Austria':
$regex = '/^(AT){0,1}U[0-9]{8}$/i';
break;
case
'Belgium':
$regex = '/^(BE){0,1}[0]{0,1}[0-9]{9}$/i';
break;
case
'Bulgaria':
$regex = '/^(BG){0,1}[0-9]{9,10}$/i';
break;
case
'Cyprus':
$regex = '/^(CY){0,1}[0-9]{8}[A-Z]$/i';
break;
case
'Czech Republic':
$regex = '/^(CZ){0,1}[0-9]{8,10}$/i';
break;
case
'Denmark':
$regex = '/^(DK){0,1}([0-9]{2}[\ ]{0,1}){3}[0-9]{2}$/i';
break;
case
'Estonia':
case
'Germany':
case
'Greece':
case
'Portugal':
$regex = '/^(EE|EL|DE|PT){0,1}[0-9]{9}$/i';
break;
case
'France':
$regex = '/^(FR){0,1}[0-9A-Z]{2}[\ ]{0,1}[0-9]{9}$/i';
break;
case
'Finland':
case
'Hungary':
case
'Luxembourg':
case
'Malta':
case
'Slovenia':
$regex = '/^(FI|HU|LU|MT|SI){0,1}[0-9]{8}$/i';
break;
case
'Ireland':
$regex = '/^(IE){0,1}[0-9][0-9A-Z\+\*][0-9]{5}[A-Z]$/i';
break;
case
'Italy':
case
'Latvia':
$regex = '/^(IT|LV){0,1}[0-9]{11}$/i';
break;
case
'Lithuania':
$regex = '/^(LT){0,1}([0-9]{9}|[0-9]{12})$/i';
break;
case
'Netherlands':
$regex = '/^(NL){0,1}[0-9]{9}B[0-9]{2}$/i';
break;
case
'Poland':
case
'Slovakia':
$regex = '/^(PL|SK){0,1}[0-9]{10}$/i';
break;
case
'Romania':
$regex = '/^(RO){0,1}[0-9]{2,10}$/i';
break;
case
'Sweden':
$regex = '/^(SE){0,1}[0-9]{12}$/i';
break;
case
'Spain':
$regex = '/^(ES){0,1}([0-9A-Z][0-9]{7}[A-Z])|([A-Z][0-9]{7}[0-9A-Z])$/i';
break;
case
'United Kingdom':
$regex = '/^(GB){0,1}([1-9][0-9]{2}[\ ]{0,1}[0-9]{4}[\ ]{0,1}[0-9]{2})|([1-9][0-9]{2}[\ ]{0,1}[0-9]{4}[\ ]{0,1}[0-9]{2}[\ ]{0,1}[0-9]{3})|((GD|HA)[0-9]{3})$/i';
break;
default:
return -
1;
break;
}

return
preg_match($regex, $vat_number);
}
?>
Kae Cyphet
14 年前
對於那些從 ereg 過來的人來說,preg_match 可能相當令人卻步。為了開始,這是一個遷移提示。

<?php
if(ereg('[^0-9A-Za-z]',$test_string)) // 如果字元不是 0-9、A-Z 或 a-z,則為 true。

if(preg_match('/[^0-9A-Za-z]/',$test_string)) // 這是 preg_match 版本。現在需要 /。
?>
akniep at rayo dot info
15 年前
preg_match 的錯誤 (PHP 版本 5.2.5)

在大多數情況下,根據您的 PHP 版本和配置,以下範例將顯示使用 preg_match 發現的兩個 PHP 錯誤之一。

<?php

$text
= "test=";
// 建立一個相當長的文字
for ($i = 0; $i++ < 100000;)
$text .= "%AB";

// 一個典型的 URL_query 有效性檢查器(此範例中模式的功能並不重要)
$pattern = '/^(?:[;\/?:@&=+$,]|(?:[^\W_]|[-_.!~*\()\[\] ])|(?:%[\da-fA-F]{2}))*$/';

var_dump( preg_match( $pattern, $text ) );

?>

可能的錯誤 (1)
=============
在我們的一台 Linux 伺服器上,上述範例會導致 PHP 執行當機並出現 C(?) 區段錯誤(!)。這似乎是一個已知的錯誤 (請參閱 http://bugs.php.net/bug.php?id=40909),但我不知道它是否已修復。
如果您正在尋找解決方法,以下程式碼片段是我發現有用的。它透過降低 PCRE 遞迴限制來包裝可能崩潰的 preg_match 呼叫,以便產生 Reg-Exp 錯誤而不是 PHP 當機。

<?php
[...]

// 降低 (可能危險的) preg_match 呼叫的 PCRE 遞迴限制
$former_recursion_limit = ini_set( "pcre.recursion_limit", 10000 );

// 包裝的 preg_match 呼叫
$result = preg_match( $pattern, $text );

// 將 PCRE 遞迴限制重設為其原始值
ini_set( "pcre.recursion_limit", $former_recursion_limit );

// 如果 reg-exp 由於降低的遞迴限制而失敗,我們可能不會做出任何陳述,但 PHP 執行會繼續
if ( PREG_RECURSION_LIMIT_ERROR === preg_last_error() )
{
// 在這裡回應失敗的正規表示式
$result = [...];

// 在這裡進行記錄或發送電子郵件
[...]
}
//if

?>

可能的錯誤 (2)
=============
在我們的一台 Windows 伺服器上,上述範例不會導致 PHP 當機,但會 (直接) 達到遞迴限制。這裡的問題是 preg_match 沒有如上述描述/手冊預期般傳回 boolean(false)。
簡而言之,如果由於 PCRE 遞迴限制而無法執行正規表示式,preg_match 似乎會傳回 int(0) 而不是預期的 boolean(false)。因此,如果 preg_match 的結果為 int(0),您似乎必須檢查 preg_last_error() 是否可能發生錯誤。
solixmexico at outlook dot com
8 年前
為了在 Windows 上驗證目錄,我使用了這個

if( preg_match("#^([a-z]{1}\:{1})?[\\\/]?([\-\w]+[\\\/]?)*$#i",$_GET['path'],$matches) !== 1 ){
echo("Invalid value");
}else{
echo("Valid value");
}

這些部分是

#^ 和 $i 使字串在整個模式中匹配,從開始到結束以確保完全匹配。
([a-z]{1}\:{1})? 字串可能以一個字母和一個冒號開頭,但每個字元只有 1 個,這用於磁碟機代號 (C:)
[\\\/]? 字串可能包含,但不需要在磁碟機代號 (\/) 後面有 1 個斜線或反斜線
([\-\w]+[\\\/]?)* 字串必須包含 1 個或多個任何字元,如連字號、字母、數字、底線,並且可能在末尾包含斜線或反斜線,以形成類似 ("/" 或 "folderName" 或 "folderName/") 的目錄,這可能會重複一次或多次。
aer0s
12 年前
簡單的函式,用於傳回遵循 preg 約定的子字串。有點昂貴,有些人可能會說懶惰,但它為我節省了時間。

# preg_substr($pattern,$subject,[$offset]) 函式
# @author aer0s
# 使用
# 正規表示式傳回字串中的特定子字串
# @param $pattern 要匹配的正規表示式模式
# @param $subject 要搜尋的字串
# @param [$offset] 要傳回的從零開始的匹配項
#
# [$offset] 預設為 0,它會傳回第一個匹配項,
# 如果 [$offset] 為 -1,則會傳回最後一個匹配項

function preg_substr($pattern,$subject,$offset=0){
preg_match_all($pattern,$subject,$matches,PREG_PATTERN_ORDER);
return $offset==-1?array_pop($matches[0]):$matches[0][$offset];
}

範例

$pattern = "/model(\s|-)[a-z0-9]/i";
$subject = "Is there something wrong with model 654, Model 732, and model 43xl or is Model aj45B the preferred choice?";

echo preg_substr($pattern,$subject);
echo preg_substr($pattern,$subject,1);
echo preg_substr($pattern,$subject,-1);

傳回類似以下內容

model 654
Model 732
Model aj45B
ASchmidt at Anamera dot net
4 年前
在 7.4 的重大變更之後,請注意 count( $matches ) 可能會有所不同,具體取決於 PREG_UNMATCHED_AS_NULL 旗標。

使用 PREG_UNMATCHED_AS_NULL 時,count( $matches ) 將永遠會是子模式的最大數量。
然而,若不使用 PREG_UNMATCHED_AS_NULL,$matches 陣列將會省略尾端任何不匹配的子模式。

僅使用 PREG_OFFSET_CAPTURE 旗標時,前兩個(共三個)匹配的結果

array (大小=3)
0 =>
array (大小=2)
0 => 字串 'may/02' (長度=6)
1 => 整數 0
1 =>
array (大小=2)
0 => 字串 'may' (長度=3)
1 => 整數 0
2 =>
array (大小=2)
0 => 字串 '02' (長度=2)
1 => 整數 4

使用額外 PREG_UNMATCHED_AS_NULL 旗標時,三個匹配中兩個的結果

array (大小=4)
0 =>
array (大小=2)
0 => 字串 'may/02' (長度=6)
1 => 整數 0
1 =>
array (大小=2)
0 => 字串 'may' (長度=3)
1 => 整數 0
2 =>
array (大小=2)
0 => 字串 '02' (長度=2)
1 => 整數 4
3 =>
array (大小=2)
0 => null
1 => 整數 -1
corey [在] effim [刪除] .com 工作
15 年前
我看到很多人嘗試組合電話號碼的正規表示式並感到掙扎(嘿,別擔心...它們很複雜)。這裡有一個我們使用的,相當不錯。它並非完美,但它應該適用於大多數非理想主義者。

*** 注意:僅匹配美國電話號碼。***

<?php

// 全部在一行...
$regex = '/^(?:1(?:[. -])?)?(?:\((?=\d{3}\)))?([2-9]\d{2})(?:(?<=\(\d{3})\))? ?(?:(?<=\d{3})[.-])?([2-9]\d{2})[. -]?(\d{4})(?: (?i:ext)\.? ?(\d{1,5}))?$/';

// 或分解開來
$regex = '/^(?:1(?:[. -])?)?(?:\((?=\d{3}\)))?([2-9]\d{2})'
.'(?:(?<=\(\d{3})\))? ?(?:(?<=\d{3})[.-])?([2-9]\d{2})'
.'[. -]?(\d{4})(?: (?i:ext)\.? ?(\d{1,5}))?$/';

?>

如果你想知道為什麼有這麼多非捕獲子模式(看起來像這樣 "(?:"),那是因為我們可以這樣做

<?php

$formatted
= preg_replace($regex, '($1) $2-$3 ext. $4', $phoneNumber);

// 或者,前提是你使用 preg_match 中的 $matches 參數

$formatted = "($matches[1]) $matches[2]-$matches[3]";
if (
$matches[4]) $formatted .= " $matches[4]";

?>

*** 結果:***
520-555-5542 :: 匹配
520.555.5542 :: 匹配
5205555542 :: 匹配
520 555 5542 :: 匹配
520) 555-5542 :: 失敗
(520 555-5542 :: 失敗
(520)555-5542 :: 匹配
(520) 555-5542 :: 匹配
(520) 555 5542 :: 匹配
520-555.5542 :: 匹配
520 555-0555 :: 匹配
(520)5555542 :: 匹配
520.555-4523 :: 匹配
19991114444 :: 失敗
19995554444 :: 匹配
514 555 1231 :: 匹配
1 555 555 5555 :: 匹配
1.555.555.5555 :: 匹配
1-555-555-5555 :: 匹配
520-555-5542 ext.123 :: 匹配
520.555.5542 EXT 123 :: 匹配
5205555542 Ext. 7712 :: 匹配
520 555 5542 ext 5 :: 匹配
520) 555-5542 :: 失敗
(520 555-5542 :: 失敗
(520)555-5542 ext .4 :: 失敗
(512) 555-1234 ext. 123 :: 匹配
1(555)555-5555 :: 匹配
geompse 在 gmail dot com
7 年前
如果輸入的 $subject 過長,此函數將會回傳 false 並發出警告。
[PhpWarning] preg_match(): Subject is too long

我相信限制是 1 或 2 GB,因為我正在使用一個 2.2GB 的字串。
雖然可能存在一個參數來改變這個限制,但在我的例子中,使用 <500MB 的字串是可行且更明智的。
cmallabon 在 homesfactory dot com
13 年前
只是一個有趣的注意事項。我只是在更新程式碼,用 strpos() 和 preg_match 來取代 ereg(),然後想到 preg_match() 可以被最佳化,以便在僅搜尋字串是否以某事物開頭時提早退出,例如
<?php
if(preg_match("/^http/", $url))
{
// 做一些事
}
?>

vs

<?php
if(strpos($url, "http") === 0)
{
// 做一些事
}
?>

正如我所猜測的,對於像 URL 這樣的短字串,strpos() 總是更快(約 2 倍),但是對於很長的好幾段文字的字串(例如,一個 XML 區塊),當字串不是以搜尋目標開頭時,preg_match 比 strpos() 快兩倍,因為它不會掃描整個字串。

因此,如果您正在搜尋長字串並期望它通常為真(例如,驗證 XML),strpos() 會快得多,但如果您期望它經常失敗,preg_match 是更好的選擇。
Frank
13 年前
如果有人來自接受 9.00 和 9,00(點或逗號)格式的小數的國家,數字驗證會像這樣
<?php
$number_check
= "9,99";
if (
preg_match( '/^[\-+]?[0-9]*\.*\,?[0-9]+$/', $number_check)) {
return
TRUE;
}
?>

但是,如果該數字將被寫入資料庫,則最有可能需要將此逗號替換為點。
這可以使用 str_replace 完成,即
<?php
$number_database
= str_replace("," , "." , $number_check);
?>
teracci2002
14 年前
當您將 preg_match() 用於安全目的或大量資料處理時,
您應該考慮 backtrack_limit 和 recursion_limit。
https://php.dev.org.tw/manual/en/pcre.configuration.php

這些限制可能會導致錯誤的匹配結果。
您可以透過檢查 preg_last_error() 來驗證是否達到這些限制。
https://php.dev.org.tw/manual/en/function.preg-last-error.php
Stefan
15 年前
我花了一段時間將我所有的 ereg() 呼叫替換為 preg_match(),因為 ereg() 現在已被棄用,並且從 v 6.0 開始將不再支援。

只是關於轉換的警告,這兩個函數的行為非常相似,但並不完全相同。顯然,您需要使用 '/' 或 '|' 字元來分隔您的模式。

讓我困惑的差異是 preg_replace 會覆寫 $matches 陣列,無論是否找到匹配項。如果沒有找到匹配項,$matches 就只是空的。

然而,如果沒有找到匹配項,ereg() 會保持 $matches 不變。在我的程式碼中,我重複呼叫 ereg,並使用每個匹配項填充 $matches。我只對最後一個匹配項感興趣。但是,使用 preg_match,如果對該函數的最後一個呼叫沒有產生匹配項,$matches 陣列將會被覆寫為空白值。

以下是一個範例程式碼片段來說明

<?php
$test
= array('yes','no','yes','no','yes','no');

foreach (
$test as $key=>$value) {
ereg("yes",$value,$matches1);
preg_match("|yes|",$value,$matches2);
}
print
"ereg result: $matches1[0]<br>";
print
"preg_match result: $matches2[0]<br>";
?>

輸出結果是
ereg result: yes
preg_match result:

(在這種情況下 $matches2[0] 是空的)

我相信 preg_match 的行為更乾淨。我只是想報告這點,希望能為其他人節省一些時間。
matt
15 年前
要支援大型 Unicode 範圍(即:[\x{E000}-\x{FFFD}] 或 \x{10FFFFF}),您必須在運算式的末尾使用修飾符 '/u'。
wjaspers4 [在] gmail [點] com
15 年前
我最近在嘗試從檔案名稱中捕獲多個具名子模式的實例時遇到問題。
因此,我想出了這個函數。

此函數允許您傳遞旗標(在此版本中,它適用於所有測試的運算式),並產生一個搜尋結果陣列。

請享用!

<?php

/**
* 允許在一個字串上測試多個表達式。
* 這會返回一個布林值,但您可能想要修改它。
*
* @author William Jaspers, IV <wjaspers4@gmail.com>
* @created 2009-02-27 17:00:00 +6:00:00 GMT
* @access public
*
* @param array $patterns 一個要測試的表達式陣列。
* @param String $subject 要測試的資料。
* @param array $findings (可選) 用於儲存結果的參數。
* @param mixed $flags 傳遞參數,允許將一般標誌應用於所有測試的表達式。
* @param array $errors 錯誤的儲存容器
*
* @returns bool 是否發生錯誤。
*/
function preg_match_multiple(
array
$patterns=array(),
$subject=null,
&
$findings=array(),
$flags=false,
&
$errors=array()
) {
foreach(
$patterns as $name => $pattern )
{
if(
1 <= preg_match_all( $pattern, $subject, $found, $flags ) )
{
$findings[$name] = $found;
} else
{
if(
PREG_NO_ERROR !== ( $code = preg_last_error() ))
{
$errors[$name] = $code;
} else
$findings[$name] = array();
}
}
return (
0===sizeof($errors));
}
?>
turabgarip at gmail dot com
3 個月前
值得注意的是,當您的字串包含實質的 Tab 字元或 Tab 字元符號時,您可能會在 regex 函式中遇到不同的結果。

如您所知,Tab 字元會與 \s 比對,因為它是空白字元。但如果我們使用數值量詞呢?例如 \s{2,}

這應該比對兩個或更多連續的空白字元,包括兩個 Tab 字元(或一個 Tab 字元和一個空格),但不只比對一個 Tab 字元。但您可能會在某些地方遇到您的實質 Tab 字元與此量詞比對的情況。這是因為某些編輯器會根據您的自動縮排設定,將 Tab 字元靜默地轉換為 2 或 4 個空格。這使得它符合 \s{2,} 的條件,因為它不再是 Tab 字元。但如果您使用 Tab 字元符號 (\t) 而不是實質的 Tab 字串,則永遠不會發生這種情況,因此它不會與此 regex 比對。
Anonymous
12 年前
這是一個減少字串內數字的函式 (有助於將 DOM 物件轉換為 simplexml 物件)

例如: decremente_chaine("somenode->anode[2]->achildnode[3]") 將會回傳 "somenode->anode[1]->achildnode[2]"

simplexml 中節點的編號從零開始,但在 DOM xpath 物件中從 1 開始

<?php
function decremente_chaine($chaine)
{
//récupérer toutes les occurrences de nombres et leurs indices
preg_match_all("/[0-9]+/",$chaine,$out,PREG_OFFSET_CAPTURE);
//parcourir les occurrences
for($i=0;$i<sizeof($out[0]);$i++)
{
$longueurnombre = strlen((string)$out[0][$i][0]);
$taillechaine = strlen($chaine);
// découper la chaine en 3 morceaux
$debut = substr($chaine,0,$out[0][$i][1]);
$milieu = ($out[0][$i][0])-1;
$fin = substr($chaine,$out[0][$i][1]+$longueurnombre,$taillechaine);
// si c'est 10,100,1000 etc. on décale tout de 1 car le résultat comporte un chiffre de moins
if(preg_match('#[1][0]+$#', $out[0][$i][0]))
{
for(
$j = $i+1;$j<sizeof($out[0]);$j++)
{
$out[0][$j][1] = $out[0][$j][1] -1;
}
}
$chaine = $debut.$milieu.$fin;
}
return
$chaine;
}
?>
skds1433 at hotmail dot com
15 年前
這是一個給正在學習使用正規表達式的人的小工具。它非常基本,並允許您嘗試不同的模式和組合。我做這個是為了幫助我,因為我喜歡嘗試不同的東西,以充分了解事物是如何運作的。

<?php
$search
= isset($_POST['search'])?$_POST['search']:"//";
$match = isset($_POST['match'])?$_POST['match']:"<>";

echo
'<form method="post">';
echo
's: <input style="width:400px;" name="search" type="text" value="'.$search.'" /><br />';
echo
'm:<input style="width:400px;" name="match" type="text" value="'.$match.'" /><input type="submit" value="go" /></form><br />';
if (
preg_match($search, $match)){echo "matches";}else{echo "no match";}
?>
ayman2243 at gmail dot com
13 年前
標示搜尋字詞

<?php
function highlight($word, $subject) {

$split_subject = explode(" ", $subject);
$split_word = explode(" ", $word);

foreach (
$split_subject as $k => $v){
foreach (
$split_word as $k2 => $v2){
if(
$v2 == $v){

$split_subject[$k] = "<span class='highlight'>".$v."</span>";

}
}
}

return
implode(' ', $split_subject);
}
?>
chris at ocproducts dot com
3 年前
如果設定了 PREG_OFFSET_CAPTURE,則未比對的捕獲 (即帶有 '?' 的捕獲) 將不會出現在結果陣列中。這可能是因為沒有偏移量,因此原始的 PHP 開發人員決定最好將其省略。
plasma
14 年前
要提取協定、主機、路徑等,只需使用

<?php

$url
= 'http://name:pass@';
$url .= 'example.com:10000';
$url .= '/path/to/file.php?a=1&amp;b=2#anchor';

$url_data = parse_url ( $url );

print_r ( $url_data );

?>
___
印出類似以下內容

陣列
(
[scheme] => http
[host] => wild.subdomain.orgy.domain.co.uk
[port] => 10000
[user] => name
[pass] => pass
[path] => /path/to/file.php
[query] => a=1&b=2
[fragment] => anchor
)

在我的測試中,parse_url 比 preg_match(_all) 快 15 倍!
itworkarounds at gmail dot com
13 年前
您可以使用以下程式碼來偵測非拉丁字元 (斯拉夫文、阿拉伯文、希臘文...)

<?php
preg_match
("/^[a-zA-Z\p{Cyrillic}0-9\s\-]+$/u", "ABC abc 1234 АБВ абв");
?>
ASchmidt at Anamera dot net
4 年前
組合標誌
PREG_OFFSET_CAPTURE | PREG_UNMATCHED_AS_NULL
不會為任何未匹配的子模式產生 NULL 值。

相反地,對於每個未匹配的子模式,仍然會產生一個陣列,其中包含

array (大小=2)
0 => null
1 => 整數 -1

因此,您的程式碼需要預期字串值為 NULL 的情況
$matches[ {子模式+1} ][0] === null
和/或負的字串偏移量
$matches[ {子模式+1} ][1] < 0
來偵測任何未匹配的子模式!
jphansen at uga dot edu
12 年前
這裡有一個正規表示式,可以用來驗證常見 MySQL 的綱要
識別符

<?php
$string
= "$table_name";
if (
preg_match("/[^\\d\\sa-zA-Z$_]/", $string))
echo
"驗證失敗";
?>
Anonymous
14 年前
將 URI 參考分解為其組件的正規表示式

^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
12 3 4 5 6 7 8 9

來源:ietf.org/rfc/rfc2396.txt
marcosc at tekar dot net
15 年前
當使用帶重音符號的字元和 "ñ" (áéíóúñ) 時,preg_match 無法運作。這是字元集問題,請使用 utf8_decode/decode 來修正。
xcsv at gmx dot net
4 年前
從 PHP 7.2 開始,您可以使用以下方法。

如果您使用具名的子模式,並且不想處理未命名的匹配結果條目和未匹配的子模式,只需將 preg_match() 替換為 named_preg_match()。這會過濾掉所有不需要的內容。

<?php
function named_preg_match(string $pattern , string $subject, array &$matches = null, int $flags = 0, int $offset = 0) {
$retval = preg_match($pattern, $subject, $localmatches, PREG_UNMATCHED_AS_NULL | $flags, $offset);
if (
$retval) {
foreach (
$localmatches as $key => $value) {
if (
is_int($key)) $value = null;
if (
is_null($value)) unset($localmatches[$key]);
}
$matches = $localmatches;
}
return
$retval;
}
?>

希望這會有所幫助。
phil dot taylor at gmail dot com
16 年前
如果您需要檢查 .com.br 和 .com.au 以及 .uk 和所有其他瘋狂的網域結尾,如果您想驗證電子郵件地址,我發現以下表達式效果很好。它在允許的範圍內相當寬鬆

<?php

$email_address
= "phil.taylor@a_domain.tv";

if (
preg_match("/^[^@]*@[^@]*\.[^@]*$/", $email_address)) {
return
"電子郵件地址";
}

?>
To Top