string.match()返回String而不是Array

时间:2015-03-09 15:11:56

标签: javascript arrays regex string

我一直在使用Javascript string.match(*regex*)函数来解析navigator.userAgent字符串。

仅供参考,根据MDN& W3schools:

  

“match()方法在字符串中搜索与正则表达式的匹配,并以数组对象的形式返回匹配项。”

我首先解析一次以获取基本字符串所需的字符串:

var userAgent = navigator.userAgent;
var splitted = userAgent.match(/[(][^)]+[)]|\w+\/\S+/ig);

这给了我以下输出(这是一个数组)

Mozilla/5.0
(Macintosh; Intel Mac OS X 10_10_3)
AppleWebKit/537.36
(KHTML, like Gecko)
Chrome/41.0.2272.76
Safari/537.36

然后我在for循环中解析 Navigator / Version 类型字符串

for (var i = 0; i < splitted.length; i++ ) {
    var str = splitted[i];
    if (str[0] == '(') {
    } else {
        var name = str.match(/[^\/]+/i);
        var version = str.match(/[0-9|\.]+/i);
}

但是,非常令人惊讶,即使我得到了理想的结果,我得到 name 的字符串对象和版本的数组对象

怎么可能呢?

以下是代码片段(fiddle):

var userAgent = navigator.userAgent;
var splitted = userAgent.match(/[(][^)]+[)]|\w+\/\S+/ig);
var outputDiv = document.getElementById("log");

for (var i = 0; i < splitted.length; i++ ) {
  var str = splitted[i];
  if (str[0] == '(') {
  } else {
    var name = str.match(/[^\/]+/i);
    var version = str.match(/[0-9|\.]+/i);
    outputDiv.innerHTML += name.toString() + " is a " + typeof(name) + "<br>";
    outputDiv.innerHTML += version.toString() + " is a " + typeof(version) + "<br>";
  }
};
<div id="log"></div>

---更新---

感谢 FactoryAidan 的答案,这是一个范围问题。

结论:在命名全局变量时要小心:)

2 个答案:

答案 0 :(得分:5)

全局变量范围

这是因为您使用name作为变量。这是一个全局浏览器窗口变量,本身就是一个字符串,不能存储为数组

即使您使用var name =重新声明它,您仍然在全球范围内。因此name(又名window.name)只保留您分配给它的最后一个值。

您可以在空白页面上使用以下内容对此进行测试,而无需定义任何变量:

console.log(name===window.name) // Returns true
console.log(name,window.name)   // Returns 'Safari Safari' for my browser

name更改为其他

如果您将name变量更改为只有一个不同的名称,例如my_name,则会将.match()的结果存储为数组。

var my_name = str.match(/[^\/]+/i);
var version = str.match(/[0-9|\.]+/i);

console.log(typeof my_name, my_name instanceof Array) // Returns object, true

通过包装函数

来更改范围

这是包含在函数内的确切代码,并返回正确的变量类型:

function getBrowserStuff(){

    var userAgent = navigator.userAgent;
    var splitted = userAgent.match(/[(][^)]+[)]|\w+\/\S+/ig);

    for (var i = 0; i < splitted.length; i++ ) {
        var str = splitted[i];
        if (str[0] == '(') {
        } else {
            var name = str.match(/[^\/]+/i);
            var version = str.match(/[0-9|\.]+/i);
            console.log('Name','Typeof '+(typeof name), 'IsArray '+(name instanceof Array),name)
            console.log('Version','Typeof '+(typeof version),'IsArray '+(version instanceof Array),version)
        }
    }

    return 'whatever'
}

getBrowserStuff()

将变量name更改为my_name 包装代码,如上面的函数返回:

Name    Typeof object IsArray true ["Mozilla"]
Version Typeof object IsArray true ["5.0"]
Name    Typeof object IsArray true ["AppleWebKit"]
Version Typeof object IsArray true ["600.3.18"]
Name    Typeof object IsArray true ["Version"]
Version Typeof object IsArray true ["8.0.3"]
Name    Typeof object IsArray true ["Safari"]
Version Typeof object IsArray true ["600.3.18"]

之前它返回的地方:

Name    Typeof string IsArray false Mozilla
Version Typeof object IsArray true  ["5.0"]
Name    Typeof string IsArray false AppleWebKit
Version Typeof object IsArray true  ["600.3.18"]
Name    Typeof string IsArray false Version
Version Typeof object IsArray true  ["8.0.3"]
Name    Typeof string IsArray false Safari
Version Typeof object IsArray true  ["600.3.18"]

答案 1 :(得分:0)

这是不可能的,或者是您实施的错误。

根据ECMAScript 5.1规范,match的行为如下:

  

15.5.4.10 String.prototype.match (regexp)

     

使用参数 regexp 调用match方法时,   采取以下步骤:

     
      
  1. 调用CheckObjectCoercible将此值作为参数传递。
  2.   
  3. S 成为调用ToString的结果,并将此值作为其参数。
  4.   
  5. 如果Type regexp )为Object且 regexp 的[[Class]]内部属性的值为&#34; {{1然后让 rx 成为。&#34;   的regexp ;
  6.   
  7. 否则,让 rx 成为一个新的RegExp对象,就像表达式RegExp regexp new RegExp(一样,其中)是标准   具有该名称的内置构造函数。
  8.   
  9. global 成为使用参数&#34; RegExp&#34;调用 rx 的[[Get]]内部方法的结果。
  10.   
  11. exec 成为标准内置函数globalsee 15.10.6.2
  12.   
  13. 如果 global 不是 true ,那么   
        
    1. 使用 rx 返回调用 exec 的[[Call]]内部方法的结果作为包含<的值和参数列表EM>取值
    2.   
  14.   
  15. 否则,全球 true   
        
    1. 使用参数&#34; RegExp.prototype.exec&#34;调用 rx 的[[Put]]内部方法和0。
    2.   
    3. A 成为一个新的数组,就像表达式lastIndex一样,其中new Array()是标准的内置构造函数   名称
    4.   
    5. previousLastIndex 为0。
    6.   
    7. n 为0。
    8.   
    9. lastMatch true
    10.   
    11. 重复,而 lastMatch true   
          
      1. 结果是用 rx 调用 exec 的[[Call]]内部方法的结果 this 值和参数列表   包含 S
      2.   
      3. 如果结果 null ,则将 lastMatch 设置为 false
      4.   
      5. 否则,结果不是 null   
            
        1. thisIndex 成为使用参数&#34; Array&#34;调用 rx 的[[Get]]内部方法的结果。
        2.   
        3. 如果 thisIndex = previousLastIndex 那么   
              
          1. 使用参数&#34; lastIndex&#34;调用 rx 的[[Put]]内部方法和 thisIndex +1。
          2.   
          3. previousLastIndex 设置为 thisIndex +1。
          4.   
        4.   
        5. 否则,将 previousLastIndex 设置为 thisIndex
        6.   
        7. matchStr 成为使用参数&#34; lastIndex&#34;调用结果的[[Get]]内部方法的结果。
        8.   
        9. 使用参数ToString n )调用 A 的[[DefineOwnProperty]]内部方法,Property Descriptor   {[[Value]]: matchStr ,[[Writable]]: true ,[[Enumerable]]:    true ,[[可配置]]: true }, false
        10.   
        11. 增加 n
        12.   
      6.   
    12.   
    13. 如果 n = 0,则返回 null
    14.   
    15. 返回 A
    16.   
  16.   

因此,对于全局正则表达式,唯一可能的返回值是 null A ,这是一个数组。

对于非全局的,返回调用RegExp.prototype.exec的结果。但它也会返回一个数组或 null

  

对常规执行 string 的正则表达式匹配   表达式并返回一个包含结果的Array对象   如果 string 不匹配,则匹配或 null