在 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 字符,但还有一种更简单的方法:只需使用仅匹配数字的正则表达式。这样你就不必使用 splittrim 或去掉任何东西:

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.

这都有效