【问题标题】:Strange behaviour with spliting a string in Javascript在Javascript中拆分字符串的奇怪行为
【发布时间】:2015-08-27 08:02:58
【问题描述】:

我正在尝试做一些相对简单的事情。我有一个日期格式为 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));

应该可以,但是我遇到了一个很奇怪的bug。

如果你试试这个代码:

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中parts的值是:ý11ý,ý06ý,ý2015 在 Chrome 中:?11?,?06?,?2015

我不明白这些神秘人物是从哪里来的!我原来的字符串只是"‎11‎/‎06‎/‎2015"

be似乎没有办法做这么简单的事情,比如从一个简单的字符串中解析一个整数。

Fiddle 没有显示隐藏的字符,但我相信它们仍然存在,因为Number("2015") 导致NaN,您可以清楚地看到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 字符。

【问题讨论】:

  • 也许这不是解决办法,但你为什么不尝试通过这样做来获取日期:var day = date[0]+date[1];
  • 我尝试了你的代码,当我重新输入日期时它工作正常,也许你有一些不可打印的字符
  • 有趣的是,我的编辑让问题消失了。它不再在 Chrome 中显示奇怪的字符。但是,是的,您的字符串中有不可打印的字符。如果您编辑代码,并将光标放在/ 之一之后并按删除键,您会注意到/ 没有被删除。这意味着有一些其他字符被删除了。
  • 你用什么做编辑?你从哪里复制日期字符串?
  • parseInt 将字符串解析为数字。在数字上使用它没有意义,并且可能会导致问题,例如parseInt(1e300, 10)

标签: javascript internet-explorer-11 parseint


【解决方案1】:

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,这都将起作用。

【讨论】:

  • 如果我可以加倍投票,我会的。乔丹的杰作!这让我难倒了将近一天,直到我将 IE 添加到我的搜索中并找到了这个。太奇怪了,这只发生在 IE 中。
【解决方案2】:

我在控制台中运行了"‎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"

【讨论】:

  • 您可以删除所有非 ASCII 字符:newDate.replace(/[^\x00-\x7F]/g, "")
  • 我会接受这个作为答案,主要是因为评论。这个: newDate.replace(/[^\x00-\x7F]/g, "") 让一切重新开始,它是最简单和最快的。
  • 你也可以只做var parts = newDate.match(/\d+/g);不管有什么无关的字符,它都会返回[ "11", "06", "2015" ]
【解决方案3】:

对于较旧的浏览器,您需要编写一个解析字符串的函数。

以下函数将创建一个Date.fromISO 方法——如果浏览器可以从 ISO 字符串中本地获取正确的日期,则使用本地方法。有些浏览器部分正确,但返回了错误的时区,因此只需检查因为 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    相关资源
    最近更新 更多