PHP 正则判断常用示例


正则判断常用示例


正文

正则匹配,我们有时会在程序中用到,但使用频率不太高,所以容易忘记,这里记一下常用的几个例子。

判断手机号:

$mobile = '18409060101';
$g = '/^1[34578]\d{9}$/';
if ( !preg_match($g, $mobile) ) {
     echo '非手机号';
}

说明:

// "^"符号表示必须是1开头;
// "[ ]"的意思是第二个数字必须是中括号中一个数字;
// 而 \d 则表示0-9任意数字,后跟{9}表示长度是9个数字;
// 后面的$表示结尾;
// 开始和结尾的 / 是正则表达式必须放在这个中间, 有的后面可能还跟模式 

还有这几种写法:

$g = '/^1[34578]{1}\d{9}$/';
$g = '/^1[34578][0-9]{9}$/';
$g = '/^(13[0-9]|15[0|3|6|7|8|9]|18[8|9])\d{8}$/';
$g = '/^(1(([35][0-9])|(47)|[8][01236789]))\d{8}$/';
$g = '/^13[\d]{9}$|^14[5,7]{1}\d{8}$|^15[^4]{1}\d{8}$|^17[0,6,7,8]{1}\d{8}$|^18[\d]{9}$/'; 

再发一个座机的:

$g = '/^0\d{2,3}(\-)?\d{7,8}$/'; 

判断邮箱:

$email = 'abc-123@123.com.cn';
$pattern = '/^([0-9A-Za-z\\-_\\.]+)@([0-9a-z]+\\.[a-z]{2,3}(\\.[a-z]{2})?)$/i';
if ( !preg_match($pattern, $email) ) {
     echo '非邮箱';
} 

说明:

// \ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。
// 例如, 'n' 匹配字符 'n'。'\n' 匹配换行符。序列 '\\' 匹配 "\",而 '\(' 则匹配 "("。
// + 匹配一个或者多个,等价于 {1,}
// ? 匹配前面的子表达式零次或一次,等价于 {0,1} ,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?
// * 匹配前面的子表达式零次或多次,等价于{0,} 。要匹配 * 字符,请使用 \*
// . 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 \.
// /内容/i 构成一个不区分大小写的正则表达式 

其他写法:

$pattern = '/^[a-z]([a-z0-9]*[-_\.]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[\.][a-z]{2,3}([\.][a-z]{2})?$/i';
$pattern = '/^[a-z]([a-z0-9]*[-_]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[\.][a-z]{2,3}([\.][a-z]{2})?$/i';
$pattern = '/^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}$/';
$pattern = '/^([a-z0-9]*[-_\.]?[a-z0-9]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[\.][a-z]{2,3}([\.][a-z]{2})?$/i';
$pattern = '/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/i'; 

碰到一个问题,就是判断一个字符串是不是数字,立刻想到正则,后来又看到了一个函数is_numeric(), 可以直接查看是否为数字串。

PCRE

regular expression, 正则表达式。

Perl 是 Practical Extraction and Report Language 的缩写,可翻译为 “实用报表提取语言”。

PCRE (Perl Compatible Regular Expressions)是一个Perl库,包括 perl 兼容的正则表达式库。

PCRE (Perl Compatible Regular Expressions 中文含义:perl语言兼容正则表达式)是一个用C语言编写的正则表达式函数库, 由菲利普.海泽(Philip Hazel)编写。PCRE是一个轻量级的函数库,比Boost之类的正则表达式库小得多。 PCRE十分易用,同时功能也很强大,性能超过了POSIX正则表达式库和一些经典的正则表达式库。

PCRE 函数:

preg_filter — 执行一个正则表达式搜索和替换
preg_grep — 返回匹配模式的数组条目
preg_last_error_msg — Returns the error message of the last PCRE regex execution
preg_last_error — 返回最后一个PCRE正则执行产生的错误代码
preg_match_all — 执行一个全局正则表达式匹配
preg_match — 执行匹配正则表达式
preg_quote — 转义正则表达式字符
preg_replace_callback_array — Perform a regular expression search and replace using callbacks
preg_replace_callback — 执行一个正则表达式搜索并且使用一个回调进行替换
preg_replace — 执行一个正则表达式的搜索和替换
preg_split — 通过一个正则表达式分隔字符串

PREG 常量:

常量     描述     自哪个版本起
PREG_PATTERN_ORDER     结果按照"规则"排序,仅用于preg_match_all(), 即$matches[0]是完整规则的匹配结果, $matches[1]是第一个子组匹配的结果,等等。     since
PREG_SET_ORDER     结果按照"集合"排序,仅用于preg_match_all(), 即$matches[0]保存第一次匹配结果的所有结果(包含子组)信息, $matches[1]保存第二次的结果信息,等等。      
PREG_OFFSET_CAPTURE     查看PREG_SPLIT_OFFSET_CAPTURE的描述。     4.3.0
PREG_SPLIT_NO_EMPTY     这个标记告诉 preg_split() 进返回非空部分。      
PREG_SPLIT_DELIM_CAPTURE     这个标记告诉 preg_split() 同时捕获括号表达式匹配到的内容。     4.0.5
PREG_SPLIT_OFFSET_CAPTURE     如果设置了这个标记,每次出现的匹配子串的偏移量也会被返回。注意,这会改变返回数组中的值, 每个元素都是由匹配子串作为第0个元素,它相对目标字符串的偏移量作为第1个元素的数组。这个 标记只能用于 preg_split()。     4.3.0
PREG_NO_ERROR     没有匹配错误时调用 preg_last_error() 返回。     5.2.0
PREG_INTERNAL_ERROR     如果有PCRE内部错误时调用 preg_last_error() 返回。     5.2.0
PREG_BACKTRACK_LIMIT_ERROR     如果调用回溯限制超出,调用preg_last_error()时返回。     5.2.0
PREG_RECURSION_LIMIT_ERROR     如果递归限制超出,调用preg_last_error()时返回。     5.2.0
PREG_BAD_UTF8_ERROR     如果最后一个错误时由于异常的utf-8数据(仅在运行在 UTF-8 模式正则表达式下可用)。 导致的,调用preg_last_error()返回。     5.2.0
PREG_BAD_UTF8_OFFSET_ERROR     如果偏移量与合法的urf-8代码不匹配(仅在运行在 UTF-8 模式正则表达式下可用)。 调用preg_last_error()返回。     5.3.0
PCRE_VERSION     PCRE版本号和发布日期(比如: "7.0 18-Dec-2006")。     5.2.4

实例

int preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] )

搜索 subject 中所有匹配 pattern 给定正则表达式的匹配结果并且将它们以 flag 指定顺序输出到 matches 中。

查找匹配 <b></b> 标签的内容:

$userinfo = "Name: <b>PHP</b> <br> Title: <b>Programming Language</b>";
preg_match_all ("/<b>(.*)<\/b>/U", $userinfo, $pat_array);
print_r($pat_array[0]);

输出:

Array
(
    [0] => <b>PHP</b>
    [1] => <b>Programming Language</b>
)

preg_match() 在第一次匹配后 将会停止搜索,返回 0 次(不匹配)或 1 次。preg_match_all() 不同于此,它会一直搜索subject 直到到达结尾。

看一个把sql数据结构转为Excel的Yii2的代码实现,用到了PhpSpreadsheet库:

/**
 * 数据库转为Excel
 * @param string $filePath
 * @return bool
 * @throws \PhpOffice\PhpSpreadsheet\Exception
 * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
 */
public function actionTableToExcel($filePath = 'vipone.sql')
{
    if (!file_exists($filePath)) {
        echo  "file is not exist: " .$filePath ."\r\n";
        return true;
    }

    $fileInfo = file_get_contents($filePath);
    preg_match_all("/CREATE TABLE[\d\D]*;[\r]?\n/U", $fileInfo, $matches);

    if (count($matches[0]) == 0) {
        echo "未匹配到数据\r\n";
        return true;
    }

    // 准备excel数据
    $excel_data = [];

    foreach ($matches[0] as $item)
    {
        // 表数据
        $table_data = [];
        // 表头数据
        $table_name_data = [];
        // 表列数据
        $table_column_data[] = ["字段", "数据类型与长度", "字段备注"];

        $explodedArray = explode("\n  ", $item);

        foreach ($explodedArray AS $key => $value)
        {
            if ($key == 0 || $key == (count($explodedArray) -1)) {
                /*分析表名及注释*/
                // 分析表名
                if ($key == 0) {
                    preg_match("/`.+`/", $value, $table_name);
                    $table_name = str_replace("`", "", $table_name[0]);

                    array_push($table_name_data, $table_name);
                }

                // 分析表名注释
                if ($key == count($explodedArray) -1) {
                    preg_match("/COMMENT='.*';/", $value, $table_name_comment);
                    if (!empty($table_name_comment[0])) {
                        $table_name_comment = str_replace("COMMENT='", "", $table_name_comment[0]);
                        $table_name_comment = str_replace("';", "", $table_name_comment);
                    } else {
                        $table_name_comment = "";
                    }

                    array_push($table_name_data, $table_name_comment);
                }
            } else {
                /*分析字段名及注释*/
                preg_match("/^`.+`/", $value, $column_name);
                if (!isset($column_name[0])) {
                    continue;
                }

                $column_name = str_replace("`", "", $column_name[0]);

                preg_match("/` [\S]+/", $value, $column_type);
                $column_type = str_replace("` ", "", $column_type[0]);

                preg_match("/COMMENT '.+'/", $value, $column_comment);
                if (!empty($column_comment[0])) {
                    $column_comment = str_replace("COMMENT '", "", $column_comment[0]);
                    $column_comment = str_replace("'", "", $column_comment);
                } else {
                    $column_comment = "";
                }

                $table_column_data[] = [$column_name, $column_type, $column_comment];
            }
        }

        array_push($table_data, ["表名", "表名备注"], $table_name_data);
        $table_data = array_merge($table_data, $table_column_data);
        $excel_data = array_merge($excel_data, $table_data, [[]], [[]]);

        unset($table_data, $table_name_data, $table_column_data);
    }

    /*导出为excel*/
    $data = $excel_data;
    $title = explode('.',$filePath)[0];

    $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
    $spreadsheet->getProperties()
        ->setCreator("vip")
        ->setLastModifiedBy("vip")
        ->setTitle( $title )
        ->setSubject( $title )
        ->setDescription( "" )
        ->setKeywords( "" )
        ->setCategory( "" );

    $sheet = $spreadsheet->getActiveSheet();
    $sheet->fromArray($data, null, 'A1');

    // 设置背景色
    foreach ($sheet->getRowIterator() as $row)
    {
        $cellIterator = $row->getCellIterator();
        foreach ($cellIterator as $cell) {
            $txt = $cell->getValue();
            if ($txt == "表名" || $txt == "表名备注" || $txt == "字段" || $txt == "数据类型与长度" || $txt == "字段备注") {
                $cell->getStyle()->getFont()->setBold(true);
                $cell->getStyle()->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setARGB('dce6f1');
//                    $sheet->getRowDimension($cell->getRow())->setRowHeight(20);
            }
        }
    }

    // 设置列宽
    $toCol = $sheet->getColumnDimension($sheet->getHighestColumn())->getColumnIndex();
    for($i = 'A'; $i <= $toCol; $i++) {
        $sheet->getColumnDimension($i)->setAutoSize(true);
    }
    $sheet->calculateColumnWidths();

    // 保存
    $fileName = "./" .$title .".xlsx";
    if (file_exists($fileName))
    {
        $fileName = "./" .$title .time() .random_int(100, 999) .".xlsx";
    }
    $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
    $writer->save( $fileName );

//        $fileName = "./" .$title .".pdf";
//        if (file_exists($fileName))
//        {
//            $fileName = "./" .$title .time() .random_int(100, 999) .".pdf";
//        }
//        $writer = new \PhpOffice\PhpSpreadsheet\Writer\Pdf\Tcpdf($spreadsheet);
//        $writer->save( $fileName );

    // 清除内存
    $spreadsheet->disconnectWorksheets();
    unset($spreadsheet);

    echo "成功:" .$fileName ."\r\n";
    return true;
}

如vipone.sql的文件内容包含:

-- ----------------------------
-- Table structure for activity
-- ----------------------------
DROP TABLE IF EXISTS `activity`;
CREATE TABLE `activity` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `unique_id` varchar(50) NOT NULL COMMENT '活动唯一标识',
  `title` varchar(50) NOT NULL COMMENT '活动名称',
  `start_time` int(11) NOT NULL COMMENT '活动开始时间',
  `stop_time` int(11) NOT NULL COMMENT '活动结束时间',
  `is_delete` tinyint(2) NOT NULL DEFAULT '0' COMMENT '是否删除',
  `rules` text NOT NULL COMMENT '领奖规则',
  `remark` varchar(2048) NOT NULL DEFAULT '' COMMENT '备注',
  `time_create` int(11) NOT NULL COMMENT '创建时间',
  `time_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_id` (`unique_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COMMENT='活动表';

导出的Excel文件内容:

POSIX

POSIX (Portable Operating System Interface) 可移植操作系统接口, 是IEEE为要在各种UNIX操作系统上运行的软件,而定义API的一系列互相关联的标准的总称。

不同内核提供的系统调用(也就是一个函数)是不同的,例如创建进程,linux下是fork函数,windows下是creatprocess函数。 好,我现在在linux下写一个程序,用到fork函数,那么这个程序该怎么往windows上移植?我需要把源代码里的fork通通改成creatprocess,然后重新编译…

posix标准的出现就是为了解决这个问题。linux和windows都要实现基本的posix标准,linux把fork函数封装成posix_fork(随便说的), windows把creatprocess函数也封装成posix_fork,都声明在unistd.h里。这样,程序员编写普通应用时候, 只用包含unistd.h,调用posix_fork函数,程序就在源代码级别可移植了。

一般情况下,应用程序通过应用编程接口(API)而不是直接通过系统调用来编程。 这点很重要,因为应用程序使用的这种编程接口实际上并不需要和内核 提供的系统调用对应。一个API定义了一组应用程序使用的编程接口。 它们可以实现成一个系统调用,也可以通过调用多个系统调用来实现,而完全不使用任何系 统调用也不存在问题。 实际上,API可以在各种不同的操作系统上实现,给应用程序提供完全相同的接口,而它们本身在这些系统上的实现却可能迥异。

在Unix世界中,最流行的应用编程接口是基于POSIX标准的。从纯技术的角度看,POSIX是由IEEE的一组标准组成, 其目标是提供一套大体上基于Unix的可移植操作系统标准。Linux是与POSIX兼容的。

POSIX是说明API和系统调用之间关系的一个极好例子。在大多数Unix系统上,根据POSIX而定义的API函数和系统调用之间有着直接关 系。 实际上,POSIX标准就是仿照早期Unix系统的界面建立的。另一方面,许多操作系统,像Windows NT,尽管和Unix没有什么关系,也提供了与POSIX兼容的库。

Linux的系统调用像大多数Unix系统一样,作为C库的一部分提供如图5-1所示。 如图5-1所示C库实现了Unix系统的主要API,包括标 准C库函数和系统调用。所有的C程序都可以使用C库,而由于C语言本身的特点, 其他语言也可以很方便地把它们封装起来使用。此外,C库提供了POSIX的 绝大部分API。

从程序员的角度看,系统调用无关紧要;他们只需要跟API打交道就可以了。相反,内核只跟系统调用打交道; 库函数及应用程序是怎么使用系统调用不是内核所关心的。






参考资料

PCRE 函数 https://www.php.net/manual/zh/ref.pcre.php

PHP 手册 函数参考 文本处理 PCRE PCRE 函数 https://www.php.net/manual/zh/function.preg-match.php

PHP 正则表达式(PCRE) https://www.runoob.com/php/php-pcre.html

http://www.cnblogs.com/blogforly/p/5644049.html

http://www.runoob.com/php/php-preg_match.html

http://www.jquerycn.cn/a_16278

http://www.runoob.com/regexp/regexp-tutorial.html

http://www.jb51.net/article/16108.htm

http://www.runoob.com/w3cnote/php-email-regrex.html

is_numeric() 函数 https://www.runoob.com/php/php-is_numeric-function.html

我从来没有真正明白:什么是POSIX? https://cloud.tencent.com/developer/ask/26856

正则表达式 - 教程 https://www.runoob.com/regexp/regexp-tutorial.html


返回