Javascript e regex: dividi la stringa e mantieni il separatore


132

Ho una stringa:

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

E vorrei dividere questa stringa con il delimitatore <br />seguito da un carattere speciale.

Per farlo, sto usando questo:

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

Sto ottenendo ciò di cui ho bisogno, tranne per il fatto che sto perdendo il delimitatore. Ecco l'esempio: http://jsfiddle.net/JwrZ6/1/

Come posso mantenere il delimitatore?


se conosci il delimitatore in anticipo, perché non farlo semplicemente ... var delim = "<br/>";?
— Andreas Wong

Grazie @SiGanteng, conosco il delimitatore in anticipo ma non riesco a farlo funzionare per il mio esempio. Devo mantenere il delimitatore in modo che sia <br /> seguito dal carattere speciale perché a volte posso avere un <br /> non seguito dal carattere speciale e questo non deve essere diviso.
— Miloš

2
Bella domanda, ho un caso simile in cui conoscere il delimitatore non aiuta. Mi divido per "] e [". Quindi in realtà il mio delimitatore è "&" ma la divisione su questo non è abbastanza precisa, ho bisogno di ottenere le parentesi su entrambi i lati per determinare una divisione corretta. Tuttavia, ho bisogno di quelle parentesi nelle mie corde divise. 1 in ciascuno, su entrambi i lati.
— PandaWood

Risposte:


104

Usa il lookahead (positivo) in modo che l'espressione regolare asserisca che il carattere speciale esiste, ma non lo corrisponde effettivamente:

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

Guardalo in azione:

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


Quando utilizzo questo codice, aggiunge un 0alla fine di ogni stringa
— keyboard-warrior

2
Non riesco a trovare nulla su lookahead positivo nel link che hai fornito.
— Paul Chris Jones,

@PaulJones il contenuto è stato spostato nel frattempo. Grazie per avermi informato, ho corretto il collegamento.
— Jon

180

Stavo avendo un problema simile ma leggermente diverso. Ad ogni modo, ecco alcuni esempi di tre diversi scenari per dove mantenere il deliminatore.

"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"]

Avvertenza: il quarto funzionerà solo per dividere singoli caratteri. ConnorsFan presenta un'alternativa :

// Split a path, but keep the slashes that follow directories
var str = 'Animation/rawr/javascript.js';
var tokens = str.match(/[^\/]+\/?|\//g);

3
Stavo cercando qualcosa come il terzo esempio, ma funziona solo se gli elementi sono solo un personaggio - altrimenti si dividerà in singoli caratteri. Alla fine ho dovuto seguire il noioso percorso RegExp.exec .
— Gordon

2
Non capisco perché tutti
— stiano

1
Come userebbe questa regex "1、2、3" .split (/ (?! 、) / G) == ["1 、", "2 、", "3"] per parole intere? Ad esempio "foo1, foo2, foo3"
— Waltari

Sei un genio!. dove trovi la documentazione che spiega come funziona? non hai bisogno della gfine
— pery mimon

1
Traduzione della .matchsoluzione non avida per questi esempi: "11、22、33".match(/.*?、|.+$/g)-> ["11、", "22、", "33"]. Il /gmodificatore di note è fondamentale per la corrispondenza.
— Beni Cherniavsky-Paskin

57

Se racchiudi il delimitatore tra parentesi, farà parte dell'array restituito.

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

A seconda della parte che desideri mantenere, cambia il sottogruppo abbinato

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

Puoi migliorare l'espressione ignorando le maiuscole / minuscole string.split (/ () & #? [A-z0-9] +; / gi);

E puoi trovare una corrispondenza per gruppi predefiniti come questo: \duguale [0-9]e \wuguale [a-zA-Z0-9_]. Ciò significa che la tua espressione potrebbe assomigliare a questa.

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

C'è un buon riferimento alle espressioni regolari su JavaScriptKit .


4
Ancora meglio, non so se possiamo mantenere solo una parte del delimitatore. Infatti devo mantenere solo il carattere speciale, posso farlo con questo: string.split (/ <br \/> (& #? [A-zA-Z0-9] +;) / g);
— Miloš

1
Puoi ottimizzare la tua espressione ignorando il caso delle parole. Oppure abbina una classe di caratteri predefinita. Aggiornerò la mia risposta.
— Torsten Walter

2
Perché è così basso .. È perfetto e così flessibile
— Tofandel

2
Questo è sicuramente il modo più semplice e la sintassi più leggibile.
— Timar Ivo Batis

4

ha risposto qui anche JavaScript Split Regular Expression mantenere il delimitatore

usa il pattern lookahead (? = pattern) nell'esempio regex

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

questo ti darà il seguente risultato.

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

Può anche essere diviso direttamente

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

dando lo stesso risultato

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

Perché non dividersi immediatamente, come nella risposta accettata di Jon?
— Gordon

@Gordon ... :) Potrei farlo ... aggiornato il codice ... Saluti
— Fry

2

Ho apportato una modifica alla risposta di jichi e l'ho inserita in una funzione che supporta anche più lettere.

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;
};

Il terzo metodo di risposte di jichi non funzionerebbe in questa funzione, quindi ho preso il quarto metodo e ho rimosso gli spazi vuoti per ottenere lo stesso risultato.

modifica: secondo metodo che esclude un array per dividere char1 o 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);
    }
};

utilizzo:

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

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

str.splitAndKeep("-") == ["first1", "-", "second2", "-", "third3", "-", "last"];

1

Una funzione di estensione divide la stringa con una sottostringa o RegEx e il delimitatore viene inserito in base al secondo parametro avanti o indietro.

    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;
    };

Il test:

    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"]);
    });

0

Ho usato questo:

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
  }, [])
}

Tranne che non dovresti scherzare String.prototype, quindi ecco una versione della funzione:

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
  }, [])
}

Quindi potresti fare:

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) )

E finirai con:

[
  "<br />&dagger; bbbb",
  "<br />&Dagger; cccc"
]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.