- 簡單的日期正則表達式
一個簡單的日期解析程序,從yyyy-mm-dd
格式的日期字符串中,分別獲取年月日。
先設置一個簡單的正則表達式,4位數字的“年”,1-2位數字的“月”和同樣1-2位數字的“日”,中間‘-’作為分隔符。程序代碼:
#include <iostream>
#include <regex>
using namespace std;
int main() {
string text = "2018-7-12";
regex pattern("[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}");
smatch results;
if ( regex_match(text, results, pattern) ) {
smatch::iterator it = results.begin();
int i = 0;
for(; it != results.end(); ++it, ++i)
cout<<i<<": "<<*it<<endl;
} else {
cout << "match failed: " <<text<< endl;
}
return 0;
}
執行輸出:
0: 2018-7-12
smatch
類型是一個匹配結果字符串列表,列表中第一個元素永遠是執行匹配操作的原始字符串,后續是根據表達式從原始字符串中解析出的子串。
程序輸出結果表示日期字符串與表達式匹配正確,但並沒有解析出各個日期字段子串。
如果需要解析出子串,則需要對表達式分組。
- 表達式分組
分組后的表達式,匹配操作才會以分組位單位輸出解析出的子串。將pattern表達式修改如下:
regex pattern("([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})");
在這里,整個表達式包含在一個圓括號里,將整個表達式作為一個分組。
執行后輸出:
0: 2018-7-12
1: 2018-7-12
下標為1的輸出項,即為整個表達式分組所匹配到的內容,也就是整個日期字符串,但這還沒有達到逐字段分解的目標,需要將分組細分。
- 表達式分組細分
將表達式改為:
regex pattern("([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})");
其中包含了3個分組(盡管后面兩個分組表達式一樣,但月份和日期的取值范圍並不完全相同,這里只簡單設置)
執行結果:
0: 2018-7-12
1: 2018
2: 7
3: 12
終於達到了日期字段分解的目標。
然后,日期字符串中,月份的表達方式可以是數字,也可以是字母名稱,如Jan,Feb,Mar等,那么就需要在表達式中兼容多種格式的日期字符串。
- 多個格式的月份表達式
當前日期字符串變更名稱月份,表達式中增加月份名稱:
string text = "2018-Jan-18";
regex pattern("([0-9]{4})-(([0-9]{1,2})|(Jan|Feb|Mar))-([0-9]{1,2})");
運行結果:
0: 2018-Jan-18
1: 2018
2: Jan
3:
4: Jan
5: 18
在這個表達式中,數字月份作為一個分組,名稱月份也是一個分組,兩者又合並成一個月份分組,因此匹配月份時,存在這三個分組(一個父分組包含2個子分組),運行輸出結果中2-4分別是這三個分組分別對月份匹配的結果,數字月份的子分組表達式沒有匹配到,因此輸出空字符串。
這樣的結果並不令人滿意,對於月份來說,只需輸出一項即可,即對於月份匹配,兩個子分組不需要單獨輸出,只需要表示月份的父級分組輸出即可。
通過將子分組指定為消極分組(Passive Group)即可。
- 消極分組
將表達式改為:
regex pattern("([0-9]{4})-((?:[0-9]{1,2})|(?:Jan|Feb|Mar))-([0-9]{1,2})");
在分組中加上 “?:” 前綴,即表示該分組位消極分組,在此表達式中,將數字月份和名稱月份的子分組都標記為消息分組,運行結果:
1: 2018
2: Jan
3: 18