En tant que programmeur PHP, nous sommes inévitablement en contact avec des expressions régulières de date. Alors en tant que programmeur, combien de solutions avez-vous pour les expressions régulières de date ? Dans cet article, nous vous amènerons à en savoir plus sur les expressions régulières de date.
1 Présentation
La régularisation de date est généralement utilisée lorsqu'il existe des exigences de format et que les données ne sont pas directement saisies par l'utilisateur. En raison des différents scénarios d'application, les règles régulières écrites sont également différentes et la complexité est naturellement différente. L'écriture régulière nécessite une analyse détaillée basée sur des situations spécifiques. Un principe de base est le suivant : n'écrivez que des situations appropriées, pas des situations complexes.
Pour l'extraction de date, tant qu'elle peut être distinguée des non-dates, écrivez simplement l'expression régulière la plus simple, telle que
\d{4}-\d{2}-\d{2}
Si aaaa-MM-jj peut être localisé de manière unique dans la chaîne source La date au format peut être utilisée pour l'extraction.
Pour la vérification, cela n'a pas beaucoup de sens si vous vérifiez simplement la composition et le format des personnages. Vous devez également ajouter la vérification des règles. En raison de l’existence d’années bissextiles, la vérification des dates devient plus compliquée.
Examinons d’abord la plage de dates valide et ce que sont les années bissextiles.
2 Règles de date
2.1 Plage de dates valide
La plage de dates valide différera selon les scénarios d'application.
La plage valide de l'objet DateTime définie dans MSDN est : 0001-01-01 00:00:00 à 9999-12-31 23:59:59.
Le 0 de l'horodatage UNIX est : 1970-01-01T00:00:00Z selon la spécification ISO 8601.
Dans les applications réelles, la plage de dates ne dépassera fondamentalement pas la plage spécifiée par DateTime, de sorte que la vérification régulière ne peut utiliser que la plage de dates couramment utilisée.
2.2 Qu'est-ce qu'une année bissextile
(Ce qui suit est tiré de l'Encyclopédie Baidu)
Une année bissextile sert à compenser l'écart entre le nombre de jours dans l'année et le nombre réel de jours sur terre causés par des réglementations de calendrier artificielles. Il est établi sur la base du décalage horaire de la période de révolution. L’année au cours de laquelle le décalage horaire est rattrapé est une année bissextile.
L'orbite de la Terre autour du soleil est de 365 jours, 5 heures, 48 minutes et 46 secondes (365,24219 jours), ce qui est une année tropicale année). L’année ordinaire du calendrier grégorien ne compte que 365 jours, soit environ 0,2422 de moins que l’année tropicale. Les jours s'accumulent environ un jour tous les quatre ans. Ce jour est ajouté à la fin du mois de février (c'est-à-dire le 29 février), de sorte que la durée de l'année devient 366 jours. Cette année est une année bissextile.
Il est à noter que le calendrier grégorien actuel est adapté du « Calendrier julien » des Romains. Parce qu'on ne comprenait pas à l'époque qu'il fallait calculer 0,0078 jours supplémentaires chaque année, de 46 avant JC au 16ème siècle, il y a eu au total 10 jours supplémentaires. Pour cette raison, le pape Grégoire XIII désigna artificiellement le 5 octobre 1582 comme le 15 octobre. Et a commencé la nouvelle réglementation des années bissextiles. C’est-à-dire qu’il est stipulé que l’année civile grégorienne est cent, et qu’elle doit être un multiple de 400 pour être une année bissextile, et si ce n’est pas un multiple de 400, c’est une année ordinaire. Par exemple, 1700, 1800 et 1900 sont des années ordinaires et 2000 est une année bissextile. Depuis, la durée annuelle moyenne est de 365,2425 jours, avec un écart de 1 jour en 4 ans environ. Selon le calcul d'une année bissextile tous les quatre ans, une moyenne de 0,0078 jours sera ajoutée chaque année. Après quatre cents ans, il y aura environ trois jours supplémentaires. Par conséquent, trois années bissextiles seront réduites tous les quatre cents ans. Le calcul des années bissextiles peut se résumer comme d'habitude : il y a un saut tous les quatre ans ; il n'y a pas de saut tous les cent ans, et il y aura un autre saut tous les quatre cents ans.
2.3 Format de date
Selon les différentes langues et cultures, les traits d'union des dates seront différents. Il existe généralement les formats suivants :
aaaaMMjj<. 🎜 >
aaaa-MM-jjaaaa/MM/jjaaaa.MM.jj3 Construction d'expressions régulières de dateFévrier des années bissextiles contient le 293.1.2 Il peut être divisé en quatre catégories selon différentes dates 3.1.3 La méthode de classification est choisie car la mise en œuvre de la classification après date est réalisée via la structure de branche de (exp1|exp2|exp3), et la structure de branche commence à partir de la branche de gauche et essaie de correspondre en séquence vers la droite. . Lorsqu'une branche correspond avec succès, elle n'essaiera plus vers la droite, sinon elle essaiera toutes les branches et signalera l'échec. Le nombre de branches et la complexité de chaque branche affecteront l'efficacité de la correspondance. Compte tenu de la distribution de probabilité des dates vérifiées, la plupart d'entre elles se situent entre 1 et 28 jours, donc l'utilisation de la deuxième méthode de classification s'améliorera efficacement. efficacité correspondante. 3.2 Implémentation régulière En utilisant la méthode de classification de la section 3.1.2, la régularité correspondante peut être écrite pour chaque règle. Ce qui suit est temporairement implémenté au format MM-dd.
先考虑与年份无关的前三条规则,年份可统一写作
(?!0000)[0-9]{4}
下面仅考虑月和日的正则
包括平年在内的所有年份的月份都包含1-28日
(0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])
包括平年在内的所有年份除2月外都包含29和30日
(0[13-9]|1[0-2])-(29|30)
包括平年在内的所有年份1、3、5、7、8、10、12月都包含31日
(0[13578]|1[02])-31)
合起来就是除闰年的2月29日外的其它所有日期
(?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)
接下来考虑闰年的实现
闰年2月包含29日
这里的月和日是固定的,就是02-29,只有年是变化的。
可通过以下代码输出所有的闰年年份,考察规则
for (int i = 1; i < 10000; i++){ if ((i % 4 == 0 && i % 100 != 0) || i % 400 == 0){ richTextBox2.Text += string.Format("{0:0000}", i) + "\n"; } }
根据闰年的规则,很容易整理出规则,四年一闰;
([0-9]{2}(0[48]|[2468][048]|[13579][26])
百年不闰,四百年再闰。
(0[48]|[2468][048]|[13579][26])00
合起来就是所有闰年的2月29日
([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29)
四条规则都已实现,且互相间没有影响,合起来就是所有符合DateTime范围的日期的正则
^((?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)|([0-9]{2}(0[48]|[2468] [048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29)$
考虑到这个正则表达式仅仅是用作验证,所以捕获组没有意义,只会占用资源,影响匹配效率,所以可以使用非捕获组来进行优化。
^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468] [048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$
以上正则年份0001-9999,格式yyyy-MM-dd。可以通过以下代码验证正则的有效性和性能
DateTime dt = new DateTime(1, 1, 1); DateTime endDay = new DateTime(9999, 12, 31); Stopwatch sw = new Stopwatch(); sw.Start(); Regex dateRegex = new Regex(@"^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$"); //Regex dateRegex = new Regex(@"^((?!0000)[0-9]{4}-((0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])|(0[13-9]|1[0-2])-(29|30)|(0[13578]|1[02])-31)|([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29)$"); Console.WriteLine("开始日期: " + dt.ToString("yyyy-MM-dd")); while (dt < endDay){ if (!dateRegex.IsMatch(dt.ToString("yyyy-MM-dd"))){ Console.WriteLine(dt.ToString("yyyy-MM-dd") + " false"); } dt = dt.AddDays(1); } if (!dateRegex.IsMatch(dt.ToString("yyyy-MM-dd"))){ Console.WriteLine(dt.ToString("yyyy-MM-dd") + " false"); } Console.WriteLine("结束日期: " + dt.ToString("yyyy-MM-dd")); sw.Stop(); Console.WriteLine("测试用时: " + sw.ElapsedMilliseconds + "ms"); Console.WriteLine("测试完成!"); Console.ReadLine();
4 日期正则表达式扩展
4.1 “年月日”形式扩展
以上实现的是yyyy-MM-dd格式的日期验证,考虑到连字符的不同,以及月和日可能为M和d,即yyyy-M-d的格式,可以对以上正则进行扩展
^(?:(?!0000)[0-9]{4}([-/.]?)(?:(?:0?[1-9]|1[0-2])([-/.]?)(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])([-/.]?)(?:29|30)|(?:0?[13578]|1[02]) ([-/.]?)31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)([-/.]?)0?2([-/.]?)29)$
使用反向引用进行简化,年份0001-9999,格式yyyy-MM-dd或yyyy-M-d,连字符可以没有或是“-”、“/”、“.”之一。
^(?:(?!0000)[0-9]{4}([-/.]?)(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])|(?:0?[13-9]|1[0-2])\1(?:29|30)| (?:0?[13578]|1[02])\1(?:31))|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)([-/.]?)0?2\2(?:29))$
这就是“年月日”这种形式最全的一个正则了,不同含义部分以不同颜色标识,可以根据自己的需要进行栽剪。
4.2 其它形式扩展
了解了以上正则各部分代表的含义,互相间的关系后,就很容易扩展成其它格式的日期正则,如dd/MM/yyyy这种“日月年”格式的日期。
^(?:(?:(?:0?[1-9]|1[0-9]|2[0-8])([-/.]?)(?:0?[1-9]|1[0-2])|(?:29|30)([-/.]?)(?:0?[13-9]|1[0-2])|31([-/.]?) (?:0?[13578]|1[02]))([-/.]?)(?!0000)[0-9]{4}|29([-/.]?)0?2([-/.]?) (?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00))$
这种格式需要注意的就是不能用反向引用来进行优了。连字符等可根据自己的需求栽剪。
4.3 添加时间的扩展
时间的规格很明确,也很简单,基本上就HH:mm:ss和H:m:s两种形式。
([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]
合入到日期的正则中,yyyy-MM-dd HH:mm:ss
^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)| (?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579] [26])00)-02-29)\s+([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$
4.4 年份定制
以上所有涉及到平年的年份里,使用的是0001-9999。当然,年份也可以根据闰年规则定制。
如年份1600-9999,格式yyyy-MM-dd或yyyy-M-d,连字符可以没有或是“-”、“/”、“.”之一。
^(?:(?:1[6-9]|[2-9][0-9])[0-9]{2}([-/.]?)(?:(?:0?[1-9]|1[0-2])\1(?:0?[1-9]|1[0-9]|2[0-8])| (?:0?[13-9]|1[0-2])\1(?:29|30)|(?:0?[13578]|1[02])\1(?:31))|(?:(?:1[6-9]|[2-9][0-9]) (?:0[48]|[2468][048]|[13579][26])|(?:16|[2468][048]|[3579][26])00)([-/.]?)0?2\2(?:29))$
5 特别说明
以上正则采用的是最基本的正则语法规则,绝大多数采用传统NFA引擎的语言都可以支持,包括JavaScript、Java、.NET等。
另外需求说明的是,虽然日期的规则相对明确,可以采用这种方式裁剪来得到符合要求的日期正则,但是并不推荐这样使用正则,正则的强大在于它的灵活性,可以根据需求,量身打造最合适的正则,如果只是用来套用模板,那正则也就不称其为正则了。
正则的语法规则并不多,而且很容易入门,掌握语法规则,量体裁衣,才是正则之“道”。
6 应用
一、首先看需求
日期的输入:
手动输入,可输入两种格式yyyymmdd或yyyy-mm-dd
二、解决思路
用户手动输入日期,需要验证输入的日期格式
用户可能的输入情况可以分为以下几种:
(1).输入为空或者为空格
(2).输入非日期格式
根据保存到数据库中的日期格式,保存的格式为yyyy-mm-dd,所以用户在输入yyyymmdd后需要进行转换,转换成yyyy-mm-dd。
思路:
验证日期格式,首现想到的是VS的验证控件,但是因为需要验证的控件有几十个,使用验证控件就需要一个个的拉控件,如果后期需要修改也很麻烦,而通过JS实现控制,再通过正则表达式对日期进行验证。
三、JS实现
//验证日期 function date(id) { var idvalue = document.getElementById(id).value; //通过查找元素 var tmpStr = ""; var strReturn = ""; //调用trim()去掉空格,因为js不支持trim() var iIdNo = trim(idvalue); //正则表达式,判断日期格式,包括日期的界限,日期的格式,平年和闰年 var v = idvalue.match(/^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$/); //输入为空时跳过检测 if (iIdNo.length == 0) { return false; } //自动更改日期格式为yyyy-mm-dd if (iIdNo.length == 8) { tmpStr = iIdNo.substring(0, 8); tmpStr = tmpStr.substring(0, 4) + "-" + tmpStr.substring(4, 6) + "-" + tmpStr.substring(6, 8) document.getElementById(id).value = tmpStr; document.getElementById(id).focus(); } //验证,判断日期格式 if ((iIdNo.length != 8) && !v) { strReturn = "日期格式错误,提示:19990101或1999-01-01"; alert(strReturn); document.getElementById(id).select(); return false; } } //运用正则表达式去除字符串两端空格(因为js不支持trim()) function trim(str) { return str.replace(/(^\s*)|(\s*$)/g, ""); } //前台调用(获得焦点触发) <input class="txtenterschooldate" size="14" type="text" id="txtenterschooldate" name="txtenterschooldate" onblur="date('txtenterschooldate')"/>
以上内容就是关于日期正则表达式的思路详解,如果大家觉得有用那就赶紧收藏起来吧。
相关推荐:
expression régulière de date php
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!