2009-12-30 80 views
4

我需要在JavaScript中编写一个分割函数,它将字符串分割为数组,逗号......但逗号不能用引号括起来( '")。只有当分隔符不用引号括起来时才分割字符串

这里有三个例子,结果(数组)如何应该是:

"peanut, butter, jelly" 
    -> ["peanut", "butter", "jelly"] 

"peanut, 'butter, bread', 'jelly'" 
    -> ["peanut", "butter, bread", "jelly"] 

'peanut, "butter, bread", "jelly"' 
    -> ["peanut", 'butter, bread', "jelly"] 

我不能使用JavaScript的split方法的原因是因为它也分裂时,分隔符用引号括起来。

如何才能做到这一点,也许正则表达式?


至于背景下,我将使用这个分裂扩大jQuery的$.expr[':']当您从传递给函数的第三个参数的第三个要素传递的参数。通常,给这个参数的名字叫做meta,它是一个包含关于过滤器的某些信息的数组。

无论如何,这个数组的第三个元素是一个字符串,它包含与过滤器一起传递的参数;并且由于字符串格式的参数,我需要能够正确地分割它们以进行解析。

+0

就可以控制整个集合,以确保所有的元素都包含在单引号内并不会包含本身内的任何单引号? – 2009-12-30 19:16:08

+0

围绕这个问题的更多背景将会很有趣。它看起来像你试图从字符串解析JavaScript,或者实际上是JSON。即使在像这样解析数组的最简单的情况下,也可能有更好的方法来处理这个问题。 – 2009-12-30 19:23:20

+0

对此,正则表达式是错误的工具,正如讨论过很多很多次一样...... – dmckee 2009-12-30 19:27:15

回答

3

你所要求的基本上是一个JavaScript CSV解析器。在“Javascript CSV解析器”上进行Google搜索,您将获得许多点击,其中很多都带有完整的脚本。又见Javascript code to parse CSV data

+0

只是为了保持平衡,对于这个问题,“词法分析器”是比“解析器”更合适的术语。 – 2009-12-31 04:51:19

1
var str = 'text, foo, "haha, dude", bar'; 
var fragments = str.match(/[a-z]+|(['"]).*?\1/g); 

更妙的是(支持逃过"'):

var str = 'text_123 space, foo, "text, here\", dude", bar, \'one, two\', blob'; 
var fragments = str.match(/[^"', ][^"',]+[^"', ]|(["'])(?:[^\1\\\\]|\\\\.)*\1/g); 

// Result: 
0: text_123 space 
1: foo 
2: "text, here\", dude" 
3: bar 
4: 'one, two' 
5: blob 
+0

不处理交换的'''和'''定界符,非alpha字符。 – 2009-12-30 19:26:16

+0

改变它,现在它:) – watain 2009-12-30 19:54:54

+0

我运行它与一个简单的测试,''a,b“'它返回'null'。显然,它不会接收包含少于3个字符的单词 – 2009-12-30 21:21:31

-1

如果你能控制输入执行该字符串将用双引号括起来",并且所有包含字符串的元素将被括在单引号'中,并且没有元素可以包含单引号,则可以分割为, '。如果你无法控制输入,那么使用正则表达式对输入进行排序/过滤/拆分将与使用正则表达式匹配xhtml一样有用(请参阅:RegEx match open tags except XHTML self-contained tags

+0

没有看到你链接的线程与这个有什么关系,好吧,在这种情况下我不会使用正则表达式,但是这里面临的问题与尝试使用正则表达式解析(x)html没有多大关系。这个*由于(x)html的递归性质而无法完成,但是这个问题根本就不是这个问题。似乎在每一个带有“regex”字样的线程中,线程(#1732348)被张贴一个链接... – 2009-12-30 19:57:16

+0

关键是,如果你不确定你的输入可能包含什么,那么没有正则表达式会解析它。 – 2009-12-30 20:09:30

+0

我的观点是,后#1732348没有什么关系这个,而且你不知道你的输入是什么,这正是正则表达式的意义:你定义了一个po的模式可能的变化。 – 2009-12-30 20:29:53

1

那么,我已经有了编写解决方案的手提钻(用于其他方面的通用代码),仅用于踢球。 。 。

function Lexer() { 
    this.setIndex = false; 
    this.useNew = false; 
    for (var i = 0; i < arguments.length; ++i) { 
    var arg = arguments [i]; 
    if (arg === Lexer.USE_NEW) { 
     this.useNew = true; 
    } 
    else if (arg === Lexer.SET_INDEX) { 
     this.setIndex = Lexer.DEFAULT_INDEX; 
    } 
    else if (arg instanceof Lexer.SET_INDEX) { 
     this.setIndex = arg.indexProp; 
    } 
    } 
    this.rules = []; 
    this.errorLexeme = null; 
} 

Lexer.NULL_LEXEME = {}; 

Lexer.ERROR_LEXEME = { 
    toString: function() { 
    return "[object Lexer.ERROR_LEXEME]"; 
    } 
}; 

Lexer.DEFAULT_INDEX = "index"; 

Lexer.USE_NEW = {}; 

Lexer.SET_INDEX = function (indexProp) { 
    if (!(this instanceof arguments.callee)) { 
    return new arguments.callee.apply (this, arguments); 
    } 
    if (indexProp === undefined) { 
    indexProp = Lexer.DEFAULT_INDEX; 
    } 
    this.indexProp = indexProp; 
}; 

(function() { 
    var New = (function() { 
    var fs = []; 
    return function() { 
     var f = fs [arguments.length]; 
     if (f) { 
     return f.apply (this, arguments); 
     } 
     var argStrs = []; 
     for (var i = 0; i < arguments.length; ++i) { 
     argStrs.push ("a[" + i + "]"); 
     } 
     f = new Function ("var a=arguments;return new this(" + argStrs.join() + ");"); 
     if (arguments.length < 100) { 
     fs [arguments.length] = f; 
     } 
     return f.apply (this, arguments); 
    }; 
    })(); 

    var flagMap = [ 
     ["global", "g"] 
    , ["ignoreCase", "i"] 
    , ["multiline", "m"] 
    , ["sticky", "y"] 
    ]; 

    function getFlags (regex) { 
    var flags = ""; 
    for (var i = 0; i < flagMap.length; ++i) { 
     if (regex [flagMap [i] [0]]) { 
     flags += flagMap [i] [1]; 
     } 
    } 
    return flags; 
    } 

    function not (x) { 
    return function (y) { 
     return x !== y; 
    }; 
    } 

    function Rule (regex, lexeme) { 
    if (!regex.global) { 
     var flags = "g" + getFlags (regex); 
     regex = new RegExp (regex.source, flags); 
    } 
    this.regex = regex; 
    this.lexeme = lexeme; 
    } 

    Lexer.prototype = { 
     constructor: Lexer 

    , addRule: function (regex, lexeme) { 
     var rule = new Rule (regex, lexeme); 
     this.rules.push (rule); 
     } 

    , setErrorLexeme: function (lexeme) { 
     this.errorLexeme = lexeme; 
     } 

    , runLexeme: function (lexeme, exec) { 
     if (typeof lexeme !== "function") { 
      return lexeme; 
     } 
     var args = exec.concat (exec.index, exec.input); 
     if (this.useNew) { 
      return New.apply (lexeme, args); 
     } 
     return lexeme.apply (null, args); 
     } 

    , lex: function (str) { 
     var index = 0; 
     var lexemes = []; 
     if (this.setIndex) { 
      lexemes.push = function() { 
      for (var i = 0; i < arguments.length; ++i) { 
       if (arguments [i]) { 
       arguments [i] [this.setIndex] = index; 
       } 
      } 
      return Array.prototype.push.apply (this, arguments); 
      }; 
     } 
     while (index < str.length) { 
      var bestExec = null; 
      var bestRule = null; 
      for (var i = 0; i < this.rules.length; ++i) { 
      var rule = this.rules [i]; 
      rule.regex.lastIndex = index; 
      var exec = rule.regex.exec (str); 
      if (exec) { 
       var doUpdate = !bestExec 
       || (exec.index < bestExec.index) 
       || (exec.index === bestExec.index && exec [0].length > bestExec [0].length) 
       ; 
       if (doUpdate) { 
       bestExec = exec; 
       bestRule = rule; 
       } 
      } 
      } 
      if (!bestExec) { 
      if (this.errorLexeme) { 
       lexemes.push (this.errorLexeme); 
       return lexemes.filter (not (Lexer.NULL_LEXEME)); 
      } 
      ++index; 
      } 
      else { 
      if (this.errorLexeme && index !== bestExec.index) { 
       lexemes.push (this.errorLexeme); 
      } 
      var lexeme = this.runLexeme (bestRule.lexeme, bestExec); 
      lexemes.push (lexeme); 
      } 
      index = bestRule.regex.lastIndex; 
     } 
     return lexemes.filter (not (Lexer.NULL_LEXEME)); 
     } 
    }; 
})(); 

if (!Array.prototype.filter) { 
    Array.prototype.filter = function (fun) { 
    var len = this.length >>> 0; 
    var res = []; 
    var thisp = arguments [1]; 
    for (var i = 0; i < len; ++i) { 
     if (i in this) { 
     var val = this [i]; 
     if (fun.call (thisp, val, i, this)) { 
      res.push (val); 
     } 
     } 
    } 
    return res; 
    }; 
} 

现在使用的代码为您的问题:

function trim (str) { 
    str = str.replace (/^\s+/, ""); 
    str = str.replace (/\s+$/, ""); 
    return str; 
} 

var splitter = new Lexer(); 
splitter.setErrorLexeme (Lexer.ERROR_LEXEME); 
splitter.addRule (/[^,"]*"[^"]*"[^,"]*/g, trim); 
splitter.addRule (/[^,']*'[^']*'[^,']*/g, trim); 
splitter.addRule (/[^,"']+/g, trim); 
splitter.addRule (/,/g, Lexer.NULL_LEXEME); 

var strs = [ 
    "peanut, butter, jelly" 
    , "peanut, 'butter, bread', 'jelly'" 
    , 'peanut, "butter, bread", "jelly"' 
    ]; 

// NOTE: I'm lazy here, so I'm using Array.prototype.map, 
//  which isn't supported in all browsers. 
var splitStrs = strs.map (function (str) { 
    return splitter.lex (str); 
}); 
相关问题