Javascript и регулярное выражение: разделите строку и сохраните разделитель

132

У меня есть строка:

var string = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc"

И я хотел бы разделить эту строку разделителем, <br />за которым следует специальный символ.

Для этого я использую это:

string.split(/<br \/>&#?[a-zA-Z0-9]+;/g);

Я получаю то, что мне нужно, за исключением того, что теряю разделитель. Вот пример: http://jsfiddle.net/JwrZ6/1/

Как сохранить разделитель?

Милош
источник
если вы заранее знаете разделитель, почему бы просто не сделать ... var delim = "<br/>";?
Андреас Вонг
Спасибо @SiGanteng, я знаю предварительный разделитель, но не могу заставить его работать в моем примере. Мне нужно, чтобы разделитель был <br />, за которым следует специальный символ, потому что иногда у меня может быть <br />, за которым не следует специальный символ, и этот не нужно разделять.
Милош
2
Хороший вопрос, у меня похожий случай, когда знание разделителя не помогает. Я разделяю на "] и [". Так что на самом деле мой разделитель - «&», но разбиение по нему недостаточно точное, мне нужно получить скобки с обеих сторон, чтобы определить правильное разделение. Однако мне нужны эти скобки обратно в мои разделенные струны. По 1 с каждой стороны.
PandaWood

Ответы:

104

Используйте (положительный) прогноз вперед, чтобы регулярное выражение утверждало, что специальный символ существует, но фактически не соответствует ему:

string.split(/<br \/>(?=&#?[a-zA-Z0-9]+;)/g);

Посмотрите это в действии:

var string = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc";
console.log(string.split(/<br \/>(?=&#?[a-zA-Z0-9]+;)/g));

Джон
источник
Когда я использую этот код, он добавляет 0в конец каждой строки
keyboard-warrior
2
Я не могу найти ничего о позитивном прогнозе в предоставленной вами ссылке.
Пол Крис Джонс,
@PaulJones: за это время контент был перемещен. Спасибо, что сообщили мне, я исправил ссылку.
Джон
180

У меня была похожая, но немного другая проблема. В любом случае, вот примеры трех разных сценариев, где хранить разделитель.

"1、2、3".split("、") == ["1", "2", "3"]
"1、2、3".split(/(、)/g) == ["1", "、", "2", "、", "3"]
"1、2、3".split(/(?=、)/g) == ["1", "、2", "、3"]
"1、2、3".split(/(?!、)/g) == ["1、", "2、", "3"]
"1、2、3".split(/(.*?、)/g) == ["", "1、", "", "2、", "3"]

Предупреждение: четвертый будет работать только для разделения отдельных символов. ConnorsFan представляет альтернативу :

// Split a path, but keep the slashes that follow directories
var str = 'Animation/rawr/javascript.js';
var tokens = str.match(/[^\/]+\/?|\//g);
Jichi
источник
3
Я искал что-то вроде третьего примера, но это работает, только если элементы представляют собой только один символ - в противном случае он будет разделен на отдельные символы. В конце концов, мне пришлось пойти по утомительному пути RegExp.exec .
Гордон
2
Я не понимаю , почему все это с помощью / г
Sarsaparilla
1
Как использовать это регулярное выражение «1、2、3» .split (/ (?! 、) / G) == [«1 、», «2 、», «3»] для полных слов? Например, «foo1, foo2, foo3»,
Waltari
Ты гений !. где найти документацию, объясняющую, как это работает? вам не нужен gконец
pery mimon
1
Перевод .matchнежадного решения для этих примеров: "11、22、33".match(/.*?、|.+$/g)-> ["11、", "22、", "33"]. /gМодификатор Note имеет решающее значение для матча.
Бени Чернявский-Паскин,
57

Если вы заключите разделитель в скобки, он будет частью возвращаемого массива.

string.split(/(<br \/>&#?[a-zA-Z0-9]+);/g);
// returns ["aaaaaa", "<br />&dagger;", "bbbb", "<br />&Dagger;", "cccc"]

В зависимости от того, какую часть вы хотите сохранить, измените, какой подгруппе вы соответствуете

string.split(/(<br \/>)&#?[a-zA-Z0-9]+;/g);
// returns ["aaaaaa", "<br />", "bbbb", "<br />", "cccc"]

Вы можете улучшить выражение, игнорируя регистр букв string.split (/ () & #? [A-z0-9] +; / gi);

И вы можете сопоставить предопределенные группы, например: \dравные [0-9]и \wравные [a-zA-Z0-9_]. Это означает, что ваше выражение лица может выглядеть так.

string.split(/<br \/>(&#?[a-z\d]+;)/gi);

На JavaScriptKit есть хороший справочник по регулярным выражениям .

Торстен Вальтер
источник
4
Более того, я не знаю, что мы можем сохранить только часть разделителя. На самом деле мне нужно оставить только специальный символ, я могу сделать это с помощью этого: string.split (/ <br \/> (& #? [A-zA-Z0-9] +;) / g);
Милош
1
Вы можете оптимизировать свое выражение, игнорируя регистр слов. Или совпадение с предопределенным классом символов. Я обновлю свой ответ.
Торстен Вальтер
2
Почему это так низко .. Это идеально и так гибко
Tofandel
2
Это, безусловно, самый простой способ и наиболее читаемый синтаксис.
Тимар Иво Батис
4

ответил на него здесь также JavaScript Split Regular Expression сохраняет разделитель

используйте шаблон просмотра вперед (? = pattern) в примере регулярного выражения

var string = '500x500-11*90~1+1';
string = string.replace(/(?=[$-/:-?{-~!"^_`\[\]])/gi, ",");
string = string.split(",");

это даст вам следующий результат.

[ '500x500', '-11', '*90', '~1', '+1' ]

Также может быть разделен напрямую

string = string.split(/(?=[$-/:-?{-~!"^_`\[\]])/gi);

дает тот же результат

[ '500x500', '-11', '*90', '~1', '+1' ]
Жарить
источник
Почему бы просто сразу не разделиться, как в принятом ответе Джона?
Гордон
@Gordon ... :) Я мог бы просто сделать это ... обновил код ... Ура
Фрай
2

Я внес изменения в ответ jichi и поместил его в функцию, которая также поддерживает несколько букв.

String.prototype.splitAndKeep = function(separator, method='seperate'){
    var str = this;
    if(method == 'seperate'){
        str = str.split(new RegExp(`(${separator})`, 'g'));
    }else if(method == 'infront'){
        str = str.split(new RegExp(`(?=${separator})`, 'g'));
    }else if(method == 'behind'){
        str = str.split(new RegExp(`(.*?${separator})`, 'g'));
        str = str.filter(function(el){return el !== "";});
    }
    return str;
};

Ответы jichi 3-й метод не будет работать в этой функции, поэтому я взял 4-й метод и удалил пустые места, чтобы получить тот же результат.

edit: второй метод, который исключает массив для разделения char1 или char2

String.prototype.splitAndKeep = function(separator, method='seperate'){
    var str = this;
    function splitAndKeep(str, separator, method='seperate'){
        if(method == 'seperate'){
            str = str.split(new RegExp(`(${separator})`, 'g'));
        }else if(method == 'infront'){
            str = str.split(new RegExp(`(?=${separator})`, 'g'));
        }else if(method == 'behind'){
            str = str.split(new RegExp(`(.*?${separator})`, 'g'));
            str = str.filter(function(el){return el !== "";});
        }
        return str;
    }
    if(Array.isArray(separator)){
        var parts = splitAndKeep(str, separator[0], method);
        for(var i = 1; i < separator.length; i++){
            var partsTemp = parts;
            parts = [];
            for(var p = 0; p < partsTemp.length; p++){
                parts = parts.concat(splitAndKeep(partsTemp[p], separator[i], method));
            }
        }
        return parts;
    }else{
        return splitAndKeep(str, separator, method);
    }
};

использование:

str = "first1-second2-third3-last";

str.splitAndKeep(["1", "2", "3"]) == ["first", "1", "-second", "2", "-third", "3", "-last"];

str.splitAndKeep("-") == ["first1", "-", "second2", "-", "third3", "-", "last"];
SwiftNinjaPro
источник
1

Функция расширения разделяет строку на подстроку или регулярное выражение, и разделитель ставится в соответствии со вторым параметром впереди или позади.

    String.prototype.splitKeep = function (splitter, ahead) {
        var self = this;
        var result = [];
        if (splitter != '') {
            var matches = [];
            // Getting mached value and its index
            var replaceName = splitter instanceof RegExp ? "replace" : "replaceAll";
            var r = self[replaceName](splitter, function (m, i, e) {
                matches.push({ value: m, index: i });
                return getSubst(m);
            });
            // Finds split substrings
            var lastIndex = 0;
            for (var i = 0; i < matches.length; i++) {
                var m = matches[i];
                var nextIndex = ahead == true ? m.index : m.index + m.value.length;
                if (nextIndex != lastIndex) {
                    var part = self.substring(lastIndex, nextIndex);
                    result.push(part);
                    lastIndex = nextIndex;
                }
            };
            if (lastIndex < self.length) {
                var part = self.substring(lastIndex, self.length);
                result.push(part);
            };
            // Substitution of matched string
            function getSubst(value) {
                var substChar = value[0] == '0' ? '1' : '0';
                var subst = '';
                for (var i = 0; i < value.length; i++) {
                    subst += substChar;
                }
                return subst;
            };
        }
        else {
            result.add(self);
        };
        return result;
    };

Тест:

    test('splitKeep', function () {
        // String
        deepEqual("1231451".splitKeep('1'), ["1", "231", "451"]);
        deepEqual("123145".splitKeep('1', true), ["123", "145"]);
        deepEqual("1231451".splitKeep('1', true), ["123", "145", "1"]);
        deepEqual("hello man how are you!".splitKeep(' '), ["hello ", "man ", "how ", "are ", "you!"]);
        deepEqual("hello man how are you!".splitKeep(' ', true), ["hello", " man", " how", " are", " you!"]);
        // Regex
        deepEqual("mhellommhellommmhello".splitKeep(/m+/g), ["m", "hellomm", "hellommm", "hello"]);
        deepEqual("mhellommhellommmhello".splitKeep(/m+/g, true), ["mhello", "mmhello", "mmmhello"]);
    });
Berezh
источник
0

Я использовал это:

String.prototype.splitBy = function (delimiter) {
  var 
    delimiterPATTERN = '(' + delimiter + ')', 
    delimiterRE = new RegExp(delimiterPATTERN, 'g');

  return this.split(delimiterRE).reduce((chunks, item) => {
    if (item.match(delimiterRE)){
      chunks.push(item)
    } else {
      chunks[chunks.length - 1] += item
    };
    return chunks
  }, [])
}

За исключением того, что вам не стоит связываться String.prototype, так что вот версия функции:

var splitBy = function (text, delimiter) {
  var 
    delimiterPATTERN = '(' + delimiter + ')', 
    delimiterRE = new RegExp(delimiterPATTERN, 'g');

  return text.split(delimiterRE).reduce(function(chunks, item){
    if (item.match(delimiterRE)){
      chunks.push(item)
    } else {
      chunks[chunks.length - 1] += item
    };
    return chunks
  }, [])
}

Итак, вы могли:

var haystack = "aaaaaa<br />&dagger; bbbb<br />&Dagger; cccc"
var needle =  '<br \/>&#?[a-zA-Z0-9]+;';
var result = splitBy(haystack , needle)
console.log( JSON.stringify( result, null, 2) )

И вы получите:

[
  "<br />&dagger; bbbb",
  "<br />&Dagger; cccc"
]
Василевич
источник