Heim > Web-Frontend > js-Tutorial > Hauptteil

Detaillierte Erläuterung der regulären Datumsausdrücke

巴扎黑
Freigeben: 2017-09-21 11:25:39
Original
1927 Leute haben es durchsucht

Datumsregulierung wird im Allgemeinen verwendet, wenn Formatanforderungen bestehen und die Daten nicht direkt vom Benutzer eingegeben werden. In diesem Artikel wird hauptsächlich die detaillierte Idee regulärer Datumsausdrücke vorgestellt. Freunde, die sie benötigen, können sich auf die folgende

1 Übersicht

Zunächst ist zu beachten, dass sowohl Winform als auch Webform über sehr ausgereifte Kalendersteuerelemente verfügen. Aus Sicht der Benutzerfreundlichkeit und Skalierbarkeit ist es besser, Kalendersteuerelemente zur Implementierung der Datumsauswahl und -überprüfung zu verwenden.

Vor ein paar Tagen habe ich Beiträge in mehreren Abschnitten von CSDN gesehen, die eine Datumsregulierung erforderten, daher habe ich diesen Artikel zusammengestellt, um mit Ihnen zu diskutieren und mit Ihnen zu kommunizieren. Wenn es Auslassungen oder Fehler gibt, korrigieren Sie mich bitte.

Datumsregulierung wird im Allgemeinen verwendet, wenn Formatanforderungen bestehen und die Daten nicht direkt vom Benutzer eingegeben werden. Aufgrund unterschiedlicher Anwendungsszenarien sind auch die regelmäßig geschriebenen Regeln unterschiedlich und die Komplexität ist natürlich unterschiedlich. Regelmäßiges Schreiben erfordert eine detaillierte Analyse anhand spezifischer Situationen. Ein Grundprinzip lautet: Schreiben Sie nur angemessene, keine komplexen.

Für die Datumsextraktion schreiben Sie einfach den einfachsten regulären Ausdruck, wie zum Beispiel


\d{4}-\d{2}-\d{2}
Nach dem Login kopieren
If, solange es von Nicht-Datumsangaben unterschieden werden kann Es kann in den Quellzeichen verwendet werden. Wenn das Datum in der Zeichenfolge eindeutig im Format jjjj-MM-tt liegt, kann es zur Extraktion verwendet werden.

Zur Überprüfung macht es wenig Sinn, wenn Sie nur die Zeichenzusammensetzung und das Format überprüfen. Sie müssen auch die Überprüfung der Regeln hinzufügen. Aufgrund der Existenz von Schaltjahren wird die Datumsüberprüfung komplizierter.

Lassen Sie uns zunächst den gültigen Datumsbereich und die Schaltjahre untersuchen.

2 Datumsregeln

2.1 Datumsgültigkeitsbereich

Die Der gültige Datumsbereich variiert je nach Anwendungsszenario.

Der gültige Bereich des in MSDN definierten DateTime-Objekts ist: 0001-01-01 00:00:00 bis 9999-12-31 23:59:59.

Die 0 des UNIX-Zeitstempels lautet: 1970-01-01T00:00:00Z gemäß der ISO 8601-Spezifikation.

In tatsächlichen Anwendungen überschreitet der Datumsbereich grundsätzlich nicht den von DateTime angegebenen Bereich, sodass bei der regelmäßigen Überprüfung nur der häufig verwendete Datumsbereich verwendet werden kann.

2.2 Was ist ein Schaltjahr?

(Das Folgende stammt aus der Baidu-Enzyklopädie)

Schaltjahr dient dazu, das auszugleichen Probleme durch künstliche Kalenderregelungen. Sie wird auf der Grundlage der Zeitdifferenz zwischen der Jahreszahl der Tage und der tatsächlichen Umlaufperiode der Erde ermittelt. Das Jahr, in dem die Zeitverschiebung ausgeglichen wird, ist ein Schaltjahr.

Die Umlaufbahn der Erde um die Sonne beträgt 365 Tage, 5 Stunden, 48 Minuten und 46 Sekunden (365,24219 Tage), was einem tropischen Jahr entspricht. Das gewöhnliche Jahr des Gregorianischen Kalenders hat nur 365 Tage, was etwa 0,2422 Tage kürzer ist als das tropische Jahr. Es addiert sich alle vier Jahre zu diesem Tag zum Ende des Monats Februar (d. h. zum 29. Februar). Die Länge des Jahres beträgt 366 Tage. Dieses Jahr ist es ein Schaltjahr.

Es ist zu beachten, dass der aktuelle Gregorianische Kalender vom „Julianischen Kalender“ der Römer übernommen wurde. Da wir damals nicht wussten, dass jedes Jahr 0,0078 zusätzliche Tage berechnet werden mussten, waren es von 46 v. Chr. bis zum 16. Jahrhundert insgesamt 10 zusätzliche Tage. Aus diesem Grund bezeichnete Papst Gregor XIII. damals den 5. Oktober 1582 künstlich als den 15. Oktober. Und begann mit den neuen Schaltjahrbestimmungen. Das heißt, es ist festgelegt, dass das gregorianische Kalenderjahr hundert ist und dass es ein Vielfaches von 400 sein muss, um ein Schaltjahr zu sein. Wenn es kein Vielfaches von 400 ist, ist es ein gewöhnliches Jahr. Beispielsweise sind 1700, 1800 und 1900 normale Jahre und 2000 ein Schaltjahr. Seitdem beträgt die durchschnittliche Jahreslänge 365,2425 Tage, mit einer Abweichung von 1 Tag in etwa 4 Jahren. Nach der Berechnung eines Schaltjahres kommen alle vier Jahre durchschnittlich 0,0078 Tage hinzu. Nach vierhundert Jahren kommen also alle vierhundert Jahre drei zusätzliche Tage hinzu. Die Berechnung von Schaltjahren lässt sich wie üblich zusammenfassen: Alle vier Jahre gibt es einen Sprung; alle hundert Jahre gibt es keinen Sprung, und alle vierhundert Jahre wird es einen weiteren Sprung geben.

2.3 Datumsformat

Je nach Sprache und Kultur sind die Bindestriche von Datumsangaben unterschiedlich, normalerweise gibt es die folgenden Formate:

JJJJMMTT

JJJJ-MM-TT

JJJJ/MM/TT

JJJJ.MM.TT

3 Konstruktion regulärer Ausdrücke mit Datum

3.1 Regelanalyse

Eine übliche Methode zum Schreiben komplexer regulärer Ausdrücke ist die erste Aufteilung Schreiben Sie die relevanten Anforderungen, schreiben Sie die entsprechenden Regeln und kombinieren Sie sie, um die gegenseitige Korrelation und den Einfluss zu überprüfen. Grundsätzlich können Sie die entsprechenden Regeln erhalten.

Gemäß der Definition eines Schaltjahres können Daten auf verschiedene Arten klassifiziert werden.

3.1.1 In zwei Kategorien unterteilt, je nachdem, ob die Anzahl der Tage mit dem Jahr zusammenhängt

In einer Kategorie, die keinen Zusammenhang hat auf das Jahr bezogen, basierend auf der Anzahl der Tage in jedem Monat. Unterschiedlich, kann in zwei Kategorien unterteilt werden

  • 1, 3, 5, 7, 8, 10 und Dezember sind 1- 31 Tage

  • April, Juni, September und November sind der 1.–30.

In einer Kategorie, die sich auf das Jahr bezieht,

  • Februar in gewöhnlichen Jahren ist der Tag 1-28

  • Februar in Schaltjahren ist der Tag 1-29

  • Alle Monate in allen Jahren enthalten die Tage 1-28

  • Alle Jahre umfassen den 29. und 30. außer Februar

  • Alle Jahre umfassen Januar, März, Mai , Juli, August, Oktober und Dezember Einschließlich des 31.

  • Der Februar in Schaltjahren umfasst den 29.

3.1.2 根据包含日期不同可划分为四类

3.1.3 分类方法选择

因为日期分类之后的实现,是要通过(exp1|exp2|exp3)这种分支结构来实现的,而分支结构是从左侧分支依次向右开始尝试匹配,当有一个分支匹配成功时,就不再向右尝试,否则尝试所有分支后并报告失败。

分支的多少,每个分支的复杂程度都会影响匹配效率,考虑到被验证日期概率分布,绝大多数都是落到1-28日内,所以采用第二种分类方法,会有效提高匹配效率。

3.2 正则实现

采用3.1.2节的分类方法,就可以针对每一个规则写出对应的正则,以下暂按MM-dd格式进行实现。

先考虑与年份无关的前三条规则,年份可统一写作


(?!0000)[0-9]{4}
Nach dem Login kopieren

下面仅考虑月和日的正则

包括平年在内的所有年份的月份都包含1-28日


(0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-8])
Nach dem Login kopieren

包括平年在内的所有年份除2月外都包含29和30日


(0[13-9]|1[0-2])-(29|30)
Nach dem Login kopieren

包括平年在内的所有年份1、3、5、7、8、10、12月都包含31日


(0[13578]|1[02])-31)
Nach dem Login kopieren

合起来就是除闰年的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)
Nach dem Login kopieren

接下来考虑闰年的实现

闰年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";
  }
}
Nach dem Login kopieren

根据闰年的规则,很容易整理出规则,四年一闰;


([0-9]{2}(0[48]|[2468][048]|[13579][26])
Nach dem Login kopieren

百年不闰,四百年再闰。


(0[48]|[2468][048]|[13579][26])00
Nach dem Login kopieren

合起来就是所有闰年的2月29日


([0-9]{2}(0[48]|[2468][048]|[13579][26])|(0[48]|[2468][048]|[13579][26])00)-02-29)
Nach dem Login kopieren

四条规则都已实现,且互相间没有影响,合起来就是所有符合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)$
Nach dem Login kopieren

考虑到这个正则表达式仅仅是用作验证,所以捕获组没有意义,只会占用资源,影响匹配效率,所以可以使用非捕获组来进行优化。


^(?:(?!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)$
Nach dem Login kopieren

以上正则年份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();
Nach dem Login kopieren

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)$
Nach dem Login kopieren

  使用反向引用进行简化,年份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))$
Nach dem Login kopieren

  这就是“年月日”这种形式最全的一个正则了,不同含义部分以不同颜色标识,可以根据自己的需要进行栽剪。

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))$
Nach dem Login kopieren

  这种格式需要注意的就是不能用反向引用来进行优了。连字符等可根据自己的需求栽剪。

4.3 添加时间的扩展

  时间的规格很明确,也很简单,基本上就HH:mm:ss和H:m:s两种形式。


([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]
Nach dem Login kopieren

  合入到日期的正则中,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]$
Nach dem Login kopieren

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))$
Nach dem Login kopieren

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(&#39;txtenterschooldate&#39;)"/>
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der regulären Datumsausdrücke. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!