按行分割javascript中的字符串,保留换行符?

时间:2012-02-02 19:25:40

标签: javascript regex newline

如何将foo\nbar\baz之类的javascript字符串拆分为一系列行,同时保留换行符?我希望['foo\n', 'bar\n', 'baz']作为输出;

我知道有很多可能的答案 - 我只是很想找到一个时髦的答案。

使用perl我会使用zero-width lookbehind assertionsplit /(?<=\n)/,但javascript正则表达式不支持它们。

PS。处理不同行结尾(至少\r\n)和处理丢失的最后一个换行符的额外点(如我的例子中所示)。

5 个答案:

答案 0 :(得分:5)

您可以使用此模式执行全局匹配:/[^\n]+(?:\r?\n|$)/g

它匹配任何非换行符,然后匹配可选的\r后跟\n或字符串的结尾。

var input = "foo\r\n\nbar\nbaz";
var result = input.match(/[^\n]+(?:\r?\n|$)/g);

结果:["foo\r\n", "bar\n", "baz"]

答案 1 :(得分:2)

怎么样?

"foo\nbar\nbaz".split(/^/m);

结果

["foo
", "bar
", "baz"]

答案 2 :(得分:0)

一个简单但粗略的方法是首先用2个特殊字符替换“\ n”。拆分第二个,并在拆分后用“\ n”替换第一个。不高效而不优雅,但绝对有效。

答案 3 :(得分:0)

由于IE的实现失败,我会使用正则表达式远离split。请改用match

'foo\n\bar\n\baz".match(/^.*(\r?\n|$)/mg)

结果:["foo\n", "bar\n", "baz"]

答案 4 :(得分:0)

评论中的其他答案和答案都有不同的缺陷。我需要一个可以在任何字符串或文件上正常工作的函数。

这是一个简单而正确的答案:

function split_lines(s) {
    return s.match(/[^\n]*\n|[^\n]+/g);
}

input = "foo\r\n\nbar\n\r\nba\rz\r\r\r";

a = split_lines(input);

Array(5) [ "foo\r\n", "\n", "bar\n", "\r\n", "ba\rz\r\r\r" ]

它有效地在每个换行符\n处分割,但包含\n,并且当且仅当不为空时,它包含最后一行且不尾随\n。它在输出中包括所有输入字符。 \r不需要任何特殊待遇。

我已经对大量随机数据进行了测试,它确实保留了所有输入字符,\n仅出现在行尾。

这是一个测试脚本:

function split_lines(s) {
    return s.match(/[^\n]*\n|[^\n]+/g);
}

function gen_random_string(n, ncharset=256, nlprob=0.05, crprob=0.05) {
    var s = "";
    for (let i = 0; i < n; ++i) {
        var r = Math.random();
        if (r < nlprob)
            s += "\n";
        else if (r < nlprob + crprob)
            s += "\r";
        else {
            var cc = Math.floor(r / (1 - nlprob - crprob) * ncharset);
            var c = String.fromCharCode(cc);
            s += c;
        }
    }
    return s;
}

function test(...args) {
    var s = gen_random_string(...args);
    console.log(`generated random string of length ${s.length} with args:`, ...args);

    var ok = true, ok1;
    var a = split_lines(s);
    console.log(`split into ${a.length} lines`);

    ok1 = s === a.join('');
    ok = ok && ok1;
    console.log("split lines combine to give the original string?", ok1 ? "OK" : "FAIL");
    for (var i = 0; i < a.length; ++i) {
        var s1 = a[i];
        ok1 = s1.endsWith("\n") || i == a.length-1;
        ok = ok && ok1;
        ok1 = !s1.slice(0, -1).includes("\n");
        ok = ok && ok1;
    }
    console.log("tested each line other than the last ends with \\n");
    console.log("tested each line does not contain \\n before the last character");
    console.log("Final result", ok ? "OK" : "FAIL");
}

test(10000, 256);
test(10000, 65536);