正文
正则匹配,我们有时会在程序中用到,但使用频率不太高,所以容易忘记,这里记一下常用的几个例子。
判断手机号:
$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