Разделить строки, но сохранить разделители в массиве разбиений - PullRequest
2 голосов
/ 24 марта 2012

С учетом строки, подобной следующей в JavaScript

var a = 'hello world\n\nbye world\n\nfoo\nbar\n\nfoo\nbaz\n\n';

Я хочу разбить ее на массив, подобный этому

['hello world', '\n\n', 'bye world', '\n\n', 'foo\nbar', '\n\n', 'foo\nbaz', '\n\n'].

Если входное значение равно var a = 'hello world\n\nbye world', результат долженbe ['hello world', '\n\n', 'bye world'].

Другими словами, я хочу разбить строку вокруг '\ n \ n' на массив так, чтобы массив также содержал '\ n \ n'.Есть ли какой-нибудь аккуратный способ сделать это в JavaScript?

1 Ответ

3 голосов
/ 24 марта 2012

Вот один вкладыш:

str.match(/\n\n|(?:[^\n]|\n(?!\n))+/g)

Вот как это работает:

  • \n\n соответствует двум последовательным символам новой строки
  • (?:[^\n]|\n(?!\n))+ соответствует любой последовательности из одного или нескольких символов
    • [^\n] не символ новой строки или
    • \n(?!\n) символ новой строки, но только если за ним не следует другой символ новой строки

Этот рекурсивный шаблон может быть применен к любой длине:

// useful function to quote strings for literal match in regular expressions
RegExp.quote = RegExp.quote || function(str) {
    return (str+"").replace(/(?=[.?*+^$[\]\\(){}|-])/g, "\\");
};
// helper function to build the above pattern recursively
function buildRecursivePattern(chars, i) {
    var c = RegExp.quote(chars[i]);
    if (i < chars.length-1) return "(?:[^" + c + "]|" + c + buildRecursivePattern(chars, i+1) + ")";
    else return "(?!" + c + ")";
}
function buildPattern(str) {
    return RegExp(RegExp.quote(delimiter) + "|" + buildRecursivePattern(delimiter.match(/[^]/g), 0) + "+", "g");
}

var str = 'hello world\n\nbye world\n\nfoo\nbar\n\nfoo\nbaz\n\n',
    delimiter = "\n\n",
    parts;
parts = str.match(buildPattern(delimiter))

Обновление Вот модификация для String.prototype.split, которая также должна добавить возможность содержать соответствующий разделитель:

if ("a".split(/(a)/).length !== 3) {
    (function() {
        var _f = String.prototype.split;
        String.prototype.split = function(separator, limit) {
            if (separator instanceof RegExp) {
                var re = new RegExp(re.source, "g"+(re.ignoreCase?"i":"")+(re.multiline?"m":"")),
                    match, result = [], counter = 0, lastIndex = 0;
                while ((match = re.exec(this)) !== null) {
                    result.push(this.substr(lastIndex, match.index-lastIndex));
                    if (match.length > 1) result.push(match[1]);
                    lastIndex = match.index + match[0].length;
                    if (++counter === limit) break;
                }
                result.push(this.substr(lastIndex));
                return result;
            } else {
                return _f.apply(arguments);
            }
        }
    })();
}
...