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.