在 Javascript 中拆分字符串的奇怪行为
Strange behaviour with spliting a string in Javascript
我正在尝试做一些相对简单的事情。我有一个这种格式的日期 dd/MM/yyyy 例如:
var newDate = "11/06/2015";
我想把它转换成日期。
此代码仅适用于 Chrome 和 Firefox:
new Date(newDate)
在 IE11 中我得到 Nan
所以我正在尝试这样做:
var parts = newDate.split("/");
var year = parts[2].trim();
var month = parts[1].trim();
var day = parts[0].trim();
var dt = new Date(Number(year), Number(month) - 1, Number(day));
应该可以,但我遇到了一个非常奇怪的错误。
如果您尝试此代码:
function myFunction() {
var newDate = "11/06/2015";
var parts = newDate.split('/');
var year = parts[2].trim();
var a = year;
var b = Number(year);
var c = parseInt(year, 10);
var d = parts;
var n = a + "<br>" + b + "<br>" + c + "<br>" + d;
document.getElementById("demo").innerHTML = n;
}
<p>Click the button to see the parse error.</p>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
然后在 IE 中它添加一个神秘字符并打印出 ý2015
并且在 chrome 中它打印出 ?2015
.
事实上,IE 中的部分值是:ý11ý,ý06ý,ý2015
在 Chrome 中:?11?,?06?,?2015
搞不懂这些神秘人物是从哪里来的!我的原始字符串只是 "11/06/2015"
似乎没有办法做这么简单的事情,比如从一个简单的字符串中解析一个整数。
Fiddle doesn't show the hidden characters but I believe they are still there because Number("2015")
results in NaN
as you can see clearly here
有什么想法吗?
更新
字符串中确实存在隐藏字符,经过调查发现它们是这样创建的:
var date = new Date();
var dateToSave = date.toLocaleDateString();
但仅限于 IE。
在 Chrome 或 Firefox 中,输出不包含 U+200E
从左到右的标记,但在 IE 中它包含!
删除 toLocaleDateString()
并将其替换为 kendo.toString(selectedValue, "dd/MM/yyyy")
解决了问题。
作为记录,我还尝试了 moment.js 和以下行:
moment(selectedValue).format("DD/MM/YYYY")
但出于某种原因,在 IE11 中,结果字符串的最开头有一个隐藏的 U+200E
字符。
对于旧版浏览器,您需要编写一个函数来解析字符串。
以下函数将创建一个 Date.fromISO
方法 - 如果浏览器可以本机从 ISO 字符串中获取正确的日期,则本机方法是 used.Some 浏览器部分正确,但返回错误的时区,所以只检查 NaN 可能不行。
(function(){
var D= new Date('2011-06-02T09:34:29+02:00');
if(!D || +D!== 1307000069000){
Date.fromISO= function(s){
var day, tz,
rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
p= rx.exec(s) || [];
if(p[1]){
day= p[1].split(/\D/);
for(var i= 0, L= day.length; i<L; i++){
day[i]= parseInt(day[i], 10) || 0;
};
day[1]-= 1;
day= new Date(Date.UTC.apply(Date, day));
if(!day.getDate()) return NaN;
if(p[5]){
tz= (parseInt(p[5], 10)*60);
if(p[6]) tz+= parseInt(p[6], 10);
if(p[4]== '+') tz*= -1;
if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
}
return day;
}
return NaN;
}
}
else{
Date.fromISO= function(s){
return new Date(s);
}
}
})()
结果将是:
var start_time = '2012-06-24T17:00:00-07:00';
var d = Date.fromISO(start_time);
var month = d.getMonth();
var day = d.getDate();
alert(++month+' '+day); // returns months from 1-12
以下功能适用于 IE 8 及以下版本。
// parse ISO format date like 2013-05-06T22:00:00.000Z
function convertDateFromISO(s) {
s = s.split(/\D/);
return new Date(Date.UTC(s[0], --s[1]||'', s[2]||'', s[3]||'', s[4]||'', s[5]||'', s[6]||''))
}
您可以像下面这样测试:
var currentTime = new Date(convertDateFromISO('2013-05-06T22:00:00.000Z')).getTime();
alert(currentTime);
我 运行 "11/06/2015".split('').map(function(s){return s.charCodeAt(0)})
(获取 Unicode 值)在我的控制台中,发现了一些有趣的东西:[8206, 49, 49, 8206, 47, 8206, 48, 54, 8206, 47, 8206, 50, 48, 49, 53]
你那里有一个 U+200E left-to-right mark。我不知道它是怎么到那里的。
去掉它,你就没事了。
在这里,您可以复制并粘贴我的字符串:"11/06/2015"
。
Scimonster 敏锐地解决了您的问题,dan 解释了如何去除非 ASCII 字符,但还有一种更简单的方法:只需使用仅匹配数字的正则表达式。这样你就不必使用 split
或 trim
或去掉任何东西:
function go() {
var newDate = "11/06/2015";
var expr = /\d+/g;
var parts = newDate.match(expr);
document.getElementById("result").innerHTML =
"Parts: " + parts +
"<br>Year: " + parts[0] +
"<br>Month: " + parts[1] +
"<br>Day: " + parts[2];
}
<button onclick="go()">Try me</button>
<div id="result"/>
无论您的字符串是 "11/06/2015"
还是 "11-6-2015"
或 junk11/06/2016junk
.
这都有效
我正在尝试做一些相对简单的事情。我有一个这种格式的日期 dd/MM/yyyy 例如:
var newDate = "11/06/2015";
我想把它转换成日期。
此代码仅适用于 Chrome 和 Firefox:
new Date(newDate)
在 IE11 中我得到 Nan
所以我正在尝试这样做:
var parts = newDate.split("/");
var year = parts[2].trim();
var month = parts[1].trim();
var day = parts[0].trim();
var dt = new Date(Number(year), Number(month) - 1, Number(day));
应该可以,但我遇到了一个非常奇怪的错误。
如果您尝试此代码:
function myFunction() {
var newDate = "11/06/2015";
var parts = newDate.split('/');
var year = parts[2].trim();
var a = year;
var b = Number(year);
var c = parseInt(year, 10);
var d = parts;
var n = a + "<br>" + b + "<br>" + c + "<br>" + d;
document.getElementById("demo").innerHTML = n;
}
<p>Click the button to see the parse error.</p>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
然后在 IE 中它添加一个神秘字符并打印出 ý2015
并且在 chrome 中它打印出 ?2015
.
事实上,IE 中的部分值是:ý11ý,ý06ý,ý2015
在 Chrome 中:?11?,?06?,?2015
搞不懂这些神秘人物是从哪里来的!我的原始字符串只是 "11/06/2015"
似乎没有办法做这么简单的事情,比如从一个简单的字符串中解析一个整数。
Fiddle doesn't show the hidden characters but I believe they are still there because Number("2015")
results in NaN
as you can see clearly here
有什么想法吗?
更新
字符串中确实存在隐藏字符,经过调查发现它们是这样创建的:
var date = new Date();
var dateToSave = date.toLocaleDateString();
但仅限于 IE。
在 Chrome 或 Firefox 中,输出不包含 U+200E
从左到右的标记,但在 IE 中它包含!
删除 toLocaleDateString()
并将其替换为 kendo.toString(selectedValue, "dd/MM/yyyy")
解决了问题。
作为记录,我还尝试了 moment.js 和以下行:
moment(selectedValue).format("DD/MM/YYYY")
但出于某种原因,在 IE11 中,结果字符串的最开头有一个隐藏的 U+200E
字符。
对于旧版浏览器,您需要编写一个函数来解析字符串。
以下函数将创建一个 Date.fromISO
方法 - 如果浏览器可以本机从 ISO 字符串中获取正确的日期,则本机方法是 used.Some 浏览器部分正确,但返回错误的时区,所以只检查 NaN 可能不行。
(function(){
var D= new Date('2011-06-02T09:34:29+02:00');
if(!D || +D!== 1307000069000){
Date.fromISO= function(s){
var day, tz,
rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
p= rx.exec(s) || [];
if(p[1]){
day= p[1].split(/\D/);
for(var i= 0, L= day.length; i<L; i++){
day[i]= parseInt(day[i], 10) || 0;
};
day[1]-= 1;
day= new Date(Date.UTC.apply(Date, day));
if(!day.getDate()) return NaN;
if(p[5]){
tz= (parseInt(p[5], 10)*60);
if(p[6]) tz+= parseInt(p[6], 10);
if(p[4]== '+') tz*= -1;
if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
}
return day;
}
return NaN;
}
}
else{
Date.fromISO= function(s){
return new Date(s);
}
}
})()
结果将是:
var start_time = '2012-06-24T17:00:00-07:00';
var d = Date.fromISO(start_time);
var month = d.getMonth();
var day = d.getDate();
alert(++month+' '+day); // returns months from 1-12
以下功能适用于 IE 8 及以下版本。
// parse ISO format date like 2013-05-06T22:00:00.000Z
function convertDateFromISO(s) {
s = s.split(/\D/);
return new Date(Date.UTC(s[0], --s[1]||'', s[2]||'', s[3]||'', s[4]||'', s[5]||'', s[6]||''))
}
您可以像下面这样测试:
var currentTime = new Date(convertDateFromISO('2013-05-06T22:00:00.000Z')).getTime();
alert(currentTime);
我 运行 "11/06/2015".split('').map(function(s){return s.charCodeAt(0)})
(获取 Unicode 值)在我的控制台中,发现了一些有趣的东西:[8206, 49, 49, 8206, 47, 8206, 48, 54, 8206, 47, 8206, 50, 48, 49, 53]
你那里有一个 U+200E left-to-right mark。我不知道它是怎么到那里的。
去掉它,你就没事了。
在这里,您可以复制并粘贴我的字符串:"11/06/2015"
。
Scimonster 敏锐地解决了您的问题,dan 解释了如何去除非 ASCII 字符,但还有一种更简单的方法:只需使用仅匹配数字的正则表达式。这样你就不必使用 split
或 trim
或去掉任何东西:
function go() {
var newDate = "11/06/2015";
var expr = /\d+/g;
var parts = newDate.match(expr);
document.getElementById("result").innerHTML =
"Parts: " + parts +
"<br>Year: " + parts[0] +
"<br>Month: " + parts[1] +
"<br>Day: " + parts[2];
}
<button onclick="go()">Try me</button>
<div id="result"/>
无论您的字符串是 "11/06/2015"
还是 "11-6-2015"
或 junk11/06/2016junk
.