Wie kann ich eine Zeichenfolge in Segmente mit n Zeichen aufteilen?


200

Wie der Titel schon sagt, habe ich eine Zeichenfolge und möchte mich in Segmente mit n Zeichen aufteilen .

Beispielsweise:

var str = 'abcdefghijkl';

Nach etwas Magie mit n=3wird es

var arr = ['abc','def','ghi','jkl'];

Gibt es eine Möglichkeit, dies zu tun?

Antworten:


358

var str = 'abcdefghijkl';
console.log(str.match(/.{1,3}/g));

Hinweis: Verwenden Sie {1,3}statt nur {3}, um den Rest für Zeichenfolgenlängen einzuschließen, die kein Vielfaches von 3 sind, z.

console.log("abcd".match(/.{1,3}/g)); // ["abc", "d"]


Noch ein paar Feinheiten:

  1. Wenn Ihre Zeichenfolge möglicherweise Zeilenumbrüche enthält ( die Sie als Zeichen zählen möchten, anstatt die Zeichenfolge zu teilen ), .werden diese nicht erfasst. Verwenden Sie /[\s\S]{1,3}/stattdessen. (Danke @Mike).
  2. Wenn Ihre Zeichenfolge leer ist, match()wird sie zurückgegeben, nullwenn Sie möglicherweise ein leeres Array erwarten. Schützen Sie sich davor durch Anhängen || [].

So können Sie am Ende mit:

var str = 'abcdef \t\r\nghijkl';
var parts = str.match(/[\s\S]{1,3}/g) || [];
console.log(parts);

console.log(''.match(/[\s\S]{1,3}/g) || []);


Dies ist technisch gesehen die bessere Antwort, da der gesamte Text aus einer Zeichenfolge abgerufen wird, die nicht gleichmäßig durch 3 teilbar ist (die letzten 2 oder 1 Zeichen).
Erik

6
Verwenden Sie [\s\S]stattdessen, .um bei Zeilenumbrüchen nicht zu versagen.
Mike Samuel

2
Möglicherweise möchten Sie in jeder Zeile einen neuen Zyklus starten. Wenn Sie wirklich Zeilenumbrüche haben, weisen diese wahrscheinlich auf eine Art Übergang hin. str.match (/. {1,3} / g) ist möglicherweise die bessere Wahl.
kennebec

+1 Sorgfältige: ''.match(/.{1,3}/g) und das ''.match(/.{3}/g)Rück nullanstelle eines leeren Array.
Web_Designer

4
Ist es möglich, eine Variable anstelle von Nummer 3 zu haben?
Ana Claudia

46

Wenn Sie keinen regulären Ausdruck verwenden möchten ...

var chunks = [];

for (var i = 0, charsLength = str.length; i < charsLength; i += 3) {
    chunks.push(str.substring(i, i + 3));
}

jsFiddle .

... sonst ist die Regex-Lösung ziemlich gut :)


1
+1 cos Ich würde dies vorziehen, wenn die 3Variable vom OP vorgeschlagen wird. Es ist besser lesbar als eine Regexp-Zeichenfolge zu verketten.
David Tang

Wenn Sie das nur in eine nützliche Funktion einpacken könnten, die sofort einsatzbereit ist
mmm

1
Dies ist mehr als 10x schneller als die Regex-Option, daher würde ich mit dieser (innerhalb einer Funktion) jsbench.github.io/#9cb819bf1ce429575f8535a211f72d5a
Job

1
Meine vorherige Aussage gilt für Chromium (außerdem war ich zu spät mit der Bearbeitung des vorherigen Kommentars, daher des neuen). Unter Firefox ist es auf meinem Computer derzeit "nur" 30% schneller, aber das ist immer noch besser.
Job

Ist das über große Saitenlängen nachhaltig?
Jacob Schneider

22
str.match(/.{3}/g); // => ['abc', 'def', 'ghi', 'jkl']

Das funktioniert bei 3mir aber kehrt nullmit zurück 250. 🤔
Jim

9

Aufbauend auf den vorherigen Antworten auf diese Frage; Die folgende Funktion teilt eine Zeichenfolge ( str) n-Anzahl ( size) von Zeichen.

function chunk(str, size) {
    return str.match(new RegExp('.{1,' + size + '}', 'g'));
}

Demo

(function() {
  function chunk(str, size) {
    return str.match(new RegExp('.{1,' + size + '}', 'g'));
  }
  
  var str = 'HELLO WORLD';
  println('Simple binary representation:');
  println(chunk(textToBin(str), 8).join('\n'));
  println('\nNow for something crazy:');
  println(chunk(textToHex(str, 4), 8).map(function(h) { return '0x' + h }).join('  '));
  
  // Utiliy functions, you can ignore these.
  function textToBin(text) { return textToBase(text, 2, 8); }
  function textToHex(t, w) { return pad(textToBase(t,16,2), roundUp(t.length, w)*2, '00'); }
  function pad(val, len, chr) { return (repeat(chr, len) + val).slice(-len); }
  function print(text) { document.getElementById('out').innerHTML += (text || ''); }
  function println(text) { print((text || '') + '\n'); }
  function repeat(chr, n) { return new Array(n + 1).join(chr); }
  function textToBase(text, radix, n) {
    return text.split('').reduce(function(result, chr) {
      return result + pad(chr.charCodeAt(0).toString(radix), n, '0');
    }, '');
  }
  function roundUp(numToRound, multiple) { 
    if (multiple === 0) return numToRound;
    var remainder = numToRound % multiple;
    return remainder === 0 ? numToRound : numToRound + multiple - remainder;
  }
}());
#out {
  white-space: pre;
  font-size: 0.8em;
}
<div id="out"></div>


2

Meine Lösung (ES6-Syntax):

const source = "8d7f66a9273fc766cd66d1d";
const target = [];
for (
    const array = Array.from(source);
    array.length;
    target.push(array.splice(0,2).join(''), 2));

Wir könnten sogar eine Funktion damit erstellen:

function splitStringBySegmentLength(source, segmentLength) {
    if (!segmentLength || segmentLength < 1) throw Error('Segment length must be defined and greater than/equal to 1');
    const target = [];
    for (
        const array = Array.from(source);
        array.length;
        target.push(array.splice(0,segmentLength).join('')));
    return target;
}

Dann können Sie die Funktion einfach und wiederverwendbar aufrufen:

const source = "8d7f66a9273fc766cd66d1d";
const target = splitStringBySegmentLength(source, 2);

Prost


2
const chunkStr = (str, n, acc) => {     
    if (str.length === 0) {
        return acc
    } else {
        acc.push(str.substring(0, n));
        return chunkStr(str.substring(n), n, acc);
    }
}
const str = 'abcdefghijkl';
const splittedString = chunkStr(str, 3, []);

Saubere Lösung ohne REGEX


1
function chunk(er){
return er.match(/.{1,75}/g).join('\n');
}

Die obige Funktion verwende ich für Base64-Chunking. Es wird ein Zeilenumbruch von jeweils 75 Zeichen erstellt.


Könnte auch tun replace(/.{1,75}/g, '$&\n').
Alex

1

Hier durchsetzen wir alle n Zeichen eine Zeichenfolge mit einer anderen Zeichenfolge:

export const intersperseString = (n: number, intersperseWith: string, str: string): string => {

  let ret = str.slice(0,n), remaining = str;

  while (remaining) {
    let v = remaining.slice(0, n);
    remaining = remaining.slice(v.length);
    ret += intersperseWith + v;
  }

  return ret;

};

wenn wir das obige wie folgt verwenden:

console.log(splitString(3,'|', 'aagaegeage'));

wir bekommen:

aag | aag | aeg | eag | e

und hier machen wir dasselbe, aber drücken auf ein Array:

export const sperseString = (n: number, str: string): Array<string> => {

  let ret = [], remaining = str;

  while (remaining) {
    let v = remaining.slice(0, n);
    remaining = remaining.slice(v.length);
    ret.push(v);
  }

  return ret;

};

und dann ausführen:

console.log(sperseString(5, 'foobarbaztruck'));

wir bekommen:

['fooba', 'rbazt', 'ruck']

Wenn jemand eine Möglichkeit kennt, den obigen Code zu vereinfachen, lmk, aber es sollte gut für Zeichenfolgen funktionieren.


Ihr erstes Snippet funktionierte nicht wie erwartet. Ich habe hier geändert: jsfiddle.net/omarojo/ksvx2txb/261
omarojo

0

Eine saubere Lösung ohne reguläre Ausdrücke:

/**
* Create array with maximum chunk length = maxPartSize
* It work safe also for shorter strings than part size
**/
function convertStringToArray(str, maxPartSize){

  const chunkArr = [];
  let leftStr = str;
  do {

    chunkArr.push(leftStr.substring(0, maxPartSize));
    leftStr = leftStr.substring(maxPartSize, leftStr.length);

  } while (leftStr.length > 0);

  return chunkArr;
};

Anwendungsbeispiel - https://jsfiddle.net/maciejsikora/b6xppj4q/ .

Ich habe auch versucht, meine Lösung mit einer regulären zu vergleichen, die als richtige Antwort ausgewählt wurde. Einige Tests finden Sie auf jsfiddle - https://jsfiddle.net/maciejsikora/2envahrk/ . Tests zeigen, dass beide Methoden eine ähnliche Leistung haben. Vielleicht ist die Regexp-Lösung auf den ersten Blick etwas schneller, aber beurteilen Sie es selbst.


0

Mit .split:

var arr = str.split( /(?<=^(?:.{3})+)(?!$)/ )  // [ 'abc', 'def', 'ghi', 'jkl' ]

und .replacewird sein:

var replaced = str.replace( /(?<=^(.{3})+)(?!$)/g, ' || ' )  // 'abc || def || ghi || jkl'



/(?!$)/ist vor dem Ende anzuhalten /$/, ohne ist:

var arr      = str.split( /(?<=^(?:.{3})+)/ )        // [ 'abc', 'def', 'ghi', 'jkl' ]     // I don't know why is not [ 'abc', 'def', 'ghi', 'jkl' , '' ], comment?
var replaced = str.replace( /(?<=^(.{3})+)/g, ' || ')  // 'abc || def || ghi || jkl || '

Gruppe ignorieren /(?:... )/ist nicht erforderlich, .replaceaber in .splitfügt Gruppen zu arr hinzu:

var arr = str.split( /(?<=^(.{3})+)(?!$)/ )  // [ 'abc', 'abc', 'def', 'abc', 'ghi', 'abc', 'jkl' ]

0

Hier ist eine Möglichkeit, dies ohne reguläre Ausdrücke oder explizite Schleifen zu tun, obwohl dadurch die Definition eines Einzeilers ein wenig erweitert wird:

const input = 'abcdefghijlkm';

// Change `3` to the desired split length.
const output = input.split('').reduce((s, c) => {let l = s.length-1; (s[l] && s[l].length < 3) ? s[l] += c : s.push(c); return s;}, []);

console.log(output);  // output: [ 'abc', 'def', 'ghi', 'jlk', 'm' ]

Es funktioniert, indem die Zeichenfolge in ein Array einzelner Zeichen aufgeteilt und dann Array.reduceüber jedes Zeichen iteriert wird. Normalerweise reducewürde ein einzelner Wert zurückgegeben, aber in diesem Fall ist der einzelne Wert zufällig ein Array, und wenn wir über jedes Zeichen gehen, hängen wir es an das letzte Element in diesem Array an. Sobald das letzte Element im Array die Ziellänge erreicht hat, fügen wir ein neues Arrayelement hinzu.


0

Kommen wir etwas später zur Diskussion, aber hier eine Variation, die etwas schneller ist als die Teilzeichenfolge + Array Push One.

// substring + array push + end precalc
var chunks = [];

for (var i = 0, e = 3, charsLength = str.length; i < charsLength; i += 3, e += 3) {
    chunks.push(str.substring(i, e));
}

Die Vorberechnung des Endwerts als Teil der for-Schleife ist schneller als die Inline-Berechnung innerhalb des Teilstrings. Ich habe es sowohl in Firefox als auch in Chrome getestet und beide zeigen eine Beschleunigung.

Sie können es hier versuchen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.