【问题标题】:RegExp works with String.match, but does not work with String.splitRegExp 适用于 String.match,但不适用于 String.split
【发布时间】:2014-09-23 16:44:09
【问题描述】:

我有一个需要解析的 CSV 文件类型。以下正是我需要考虑的条件(缺少列标题、引号内的换行符、缺少数据等):

ID,NAME,TITLE,DESCRIPTION,,
PRO1234,"JOHN SMITH",ENGINEER,"JOHN HAS BEEN WORKING

HARD ON BEING A GOOD

SERVENT."
PRO1235,"KEITH SMITH",ENGINEER,"keith has been working

hard on being a good

servent."
PRO1235,"KENNY SMITH",,"keith has been working

hard on being a good

servent."
PRO1235,"RICK SMITH",,,

您会注意到说明中有换行符以及新数据行的换行符。

我编写了这个正则表达式来查找引号之外的换行符,它非常有效here

代码,使用 Node.js:

var fs = require('fs');

function parseCSV(filename){
    var rx = new RegExp(/\n(?=([^"\\]*(\\.|"([^"\\]*\\.)*[^"\\]*"))*[^"]*$)/g);
    var strFile = fs.readFileSync(filename).toString();
    console.log("line feed count via match: " + strFile.match(rx).length);
    var csv = strFile.split(rx);

    console.log("csv length: " + csv.length);
    console.log("csv items ###############################");
    csv.forEach(function(e,i,a){
        console.log("item e: " + e);
    });
}

当我运行此程序时,您会看到换行数(通过匹配找到的换行)是正确的,即 4。然而,当使用 String.split() 相同的 ret 时,它返回 17 并且结果数组是不稳定的:

line feed count via match: 4
csv length: 17
csv items ###############################
item e: ID,NAME,TITLE,DESCRIPTION,,
item e: 
PRO1235,"RICK SMITH"
item e: "RICK SMITH"
item e: undefined
item e: PRO1234,"JOHN SMITH",ENGINEER,"JOHN HAS BEEN WORKING

HARD ON BEING A GOOD

SERVENT."
item e: 
PRO1235,"RICK SMITH"
item e: "RICK SMITH"
item e: undefined
item e: PRO1235,"KEITH SMITH",ENGINEER,"keith has been working

hard on being a good

servent."
item e: 
PRO1235,"RICK SMITH"
item e: "RICK SMITH"
item e: undefined
item e: PRO1235,"KENNY SMITH",,"keith has been working

hard on being a good

servent."
item e: PRO1235,"RICK SMITH"
item e: "RICK SMITH"
item e: undefined
item e: PRO1235,"RICK SMITH",,,

我在拆分时做错了什么?我的想法是,如果我可以识别 4 个与 match() 完美配合的换行符,那么同一个正则表达式应该提供“拆分”字符串的位置。

【问题讨论】:

  • 重新发明轮子的经典案例。 Why not use a dedicated CSV parser for this?
  • 首先你不能从它们中间开始解析字符串。
  • sln - 你能解释一下你的评论吗?如果我正在调用 string.split(regExp),我如何解析中间的字符串?
  • 您是否尝试解析 csv 文件?如果是这样,这个正则表达式将在有/没有你的换行问题的情况下处理它。 /(?:(?:^|,|\r?\n)\s*)(?:"([^"\\]*(?:\\[\S\s][^"\\]*)*)"(?:\s*(?:(?=,|\r?\n)|$))|([^,]*)(?:\s*(?:(?=,)|$)))/字段值为$1$2

标签: javascript regex string split match


【解决方案1】:

您的捕获组过多。 Split 将在拆分字符串时返回捕获的组。 考虑以下简单示例:

var simpleString = "111aaa222bbb";
var regxNoCaptureGroup = /\d+/;
var regxWithCaptureGroup = /(\d+)/;
var regxWithNoncapturingGroup = /(?:\d+)/;

simpleString.split(regxNoCaptureGroup); //["", "aaa", "bbb"]
simpleString.split(regxWithNoncapturingGroup); //same as above
simpleString.split(regxWithCaptureGroup); //["", "111", "aaa", "222", "bbb"]  - includes captured groups

您在捕获组中有捕获组。请记住, split 将找到组,并将其删除以找到拆分部分,因此围绕数字拆分(如第一个示例中所示)将仅返回字母。 在您的情况下,它将删除捕获的任何内容。 使用捕获组,它会在结果中返回它们 - 因此,如果您计划将 split 与正则表达式一起使用,您可能应该构建一个只捕获所需内容的好的正则表达式。

【讨论】:

  • 谢谢 Etai,我会看看我的 regExp - 感谢您的解释和时间 - 它确实有道理。
  • np。由于它回答了您有关拆分与匹配的问题,请随时将其标记为已接受的答案:)
【解决方案2】:

感谢 anubhava 的回答,效果很好:

var $ = jQuery = require('jquery');
var csv = require('./jquery.csv-0.71.min.js');
var fs = require('fs');

var strFile = fs.readFileSync("./data/TestData.csv").toString();
var obj = $.csv.toObjects(strFile);
var str = JSON.stringify(obj, null, 4);

console.log("str: " + str);

谁不喜欢一套新的轮子?

在我的辩护中,我在 node 上尝试了 3 个工具,所有 3 个工具都是为最简单的情况和原始状态的文件编写的。

【讨论】:

    猜你喜欢
    • 2019-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-31
    • 2020-11-23
    • 2018-09-08
    相关资源
    最近更新 更多