输入日期的检测
(一) 最近用VS2005开发ASP.Net页面,用到了验证控件,验证日期时,学了一点正则表达式的写法,发现书上的一种写法无法验证,于是自己写了一下,请大家多多指教。
书上的写法: "/(?:0[1-9]|[12]][0-9]|3[01])\ /(?:0[1-9]|1[0-2])\ /(?:19|20\d{2})/"
验证的日期格式为: "dd/mm/yyyy"
我的写法: "((19|20)\d{2})/((0[1-9])|(1[0-2]))/((0[1-9])|([12][0-9])|(3[01]))"
验证的日期格式为: "yyyy/mm/dd"
如果将输入的最大长度定为 10,可以少很多麻烦。
(二) 扩展
正则表达式写为: "((19|20)\d{2})(/|-| |.)((0[1-9])|(1[0-2]))(/|-| |.)((0[1-9])|([12][0-9])|(3[01]))\s*"
这样,在年月与月日之间的分隔符就可以是'/', '-', '.', ' ', '',及支持的格式扩大为:
(1)"yyyy/mm/dd" (2)"yyyy-mm-dd" (3)"yyyy.mm.dd" (4)"yyyy mm dd"
而且在正则表达式后面增加了"\s*",这样,在输入完日期后,即使不小心多输了空白字符,也不会算错。
但这样扩展之后,会出现一种错误的格式,如"yyyy/mm-dd",这种格式在验证时,不会出错,但转换为时间的时候就有问题了,因此要增加一些限制,我采取的做法是增加javascript检测,如下:
function checkSeparator()
{
var sInput;
sInput = document.getElementById("TextDate").value; //获取输入字符串
if((sInput.indexOf("/") > 0) && (sInput.indexOf("/") == sInput.lastIndexOf("/")))
{
alert("分隔符不一致!");
return false;
}
if((sInput.indexOf("-") > 0) && (sInput.indexOf("-") == sInput.lastIndexOf("-")))
{
alert("分隔符不一致!");
return false;
}
if((sInput.indexOf(".") > 0) && (sInput.indexOf(".") == sInput.lastIndexOf(".")))
{
alert("分隔符不一致!");
return false;
}
if((sInput.indexOf(" ") > 0) && (sInput.indexOf(" ") == sInput.lastIndexOf(" ")))
{
alert("分隔符不一致!");
return false;
}
return true;
}
这样,就可以把分隔符不一致的情况排除。
(三)也许,细心一点的读者已经发现了上面这两种方法都存在缺陷。
(1)日期验证不够精确,如1,3,5,7,8,10,12月都是31天;4,6,9,11月都是30天,2月28天或29天;
(2)在扩展中允许最后输入空格,在判断空格为分隔符时,meiyou排除最后的空格带来的影响。(调查结果javascript的String对象的方法中没有找到trim()方法,恐怕要自己写trim()函数来去除结尾的空白,由于空白字符是看不见的,如果结尾有空白算错误的话,用户也许会产生迷惑,因为表面看来输入日期是正确的)
自己用javascript写个trim()函数并不难(除非你不会javascript),在这里只给出缺陷(1)的解决办法。由于在验证表达式中判断闰年很复杂,这里给出一种javascript判断日期的方法。
function checkStrDate(strSearchDate)
{
if(strSearchDate.length <= 0)
{
return true;
}
var strMsg="日期格式不正确";
var arrSeparators = "/-. "
var currSep = 0;
var iPosFirst = -1;
var iPosLast = -1;
var bNumValid = false;
for (var i=0; i < 4; i++)
{
currSep = arrSeparators.charAt(i);
iPosFirst = strSearchDate.indexOf(currSep);
iPosLast = strSearchDate.lastIndexOf(currSep);
if((iPosFirst > 0) && (iPosLast > 0) && (iPosFirst != iPosLast))
{
var strArrTmp = strSearchDate.split(currSep,3);
var year = Number(strArrTmp[0],10);
if(year != year) continue;
var month = Number(strArrTmp[1],10);
if(month != month) continue;
var day = Number(strArrTmp[2],10);
if(day != day) continue;
bNumValid = true;
break;
}
}
if(!bNumValid)
{
var iPosYear = strSearchDate.indexOf("年",0);
if( iPosYear < 0)
{
alert(strMsg);
return false;
}
var iPosMonth = strSearchDate.indexOf("月",iPosYear);
if( iPosMonth < 0)
{
alert(strMsg);
return false;
}
var iPosDay = strSearchDate.indexOf("日",iPosMonth);
if( iPosDay < 0)
{
iPosDay = strSearchDate.length;
}
var sYear = strSearchDate.substring(0,iPosYear);
var sMonth = strSearchDate.substring(iPosYear+1,iPosMonth);
var sDay = strSearchDate.substring(iPosMonth+1,iPosDay);
var year = Number(sYear,10);
if(year != year)
{
alert(strMsg);
return false;
}
var month = Number(sMonth, 10);
if(month != month)
{
alert(strMsg);
return false;
}
var day = Number(sDay,10);
if(day != day)
{
alert(strMsg);
return false;
}
bNumValid = true;
}
if(!bNumValid)
{
alert(strMsg);
return false;
}
if((year > 2099) || (year < 1900))
{
alert(strMsg);
return false;
}
if((month > 12) || (month < 1))
{
alert(strMsg);
return false;
}
if((day > 31) || (day < 1))
{
alert(strMsg);
return false;
}
if((day > 30) && ((month == 4) || (month == 6) || (month == 9) || (month == 11)))
{
alert(strMsg);
return false;
}
var bLeapYear=((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
if((bLeapYear) && ((month == 2) && (day > 29)))
{
alert(strMsg);
return false;
}
if((!bLeapYear) && ((month == 2) && (day > 28)))
{
alert(strMsg);
return false;
}
return true;
}
应用这种方法,可以不使用验证控件。这里多了对“年月日”的支持,值得注意的是,在javascript中,一个汉字于一个英文字符所占的空间是一样的。
注:本文代码在VS2005运行正常