Bagaimana saya bisa membagi string menjadi segmen n karakter?

201

Seperti judulnya, saya punya string dan saya ingin membagi menjadi segmen n karakter.

Sebagai contoh:

var str = 'abcdefghijkl';

setelah beberapa sihir dengan n=3, itu akan menjadi

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

Apakah ada cara untuk melakukan ini?

Ben
sumber

Jawaban:

359

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

Catatan: Gunakan {1,3}sebagai ganti hanya {3}untuk memasukkan sisa untuk panjang string yang bukan kelipatan 3, misalnya:

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


Beberapa kehalusan:

  1. Jika string Anda mungkin berisi baris baru ( yang ingin Anda hitung sebagai karakter daripada memisahkan string ), maka string. tidak akan menangkapnya. Gunakan /[\s\S]{1,3}/sebagai gantinya. (Trims @Mike).
  2. Jika string Anda kosong, maka match()akan kembali nullketika Anda mungkin mengharapkan array kosong. Lindungi dari ini dengan menambahkan || [].

Jadi, Anda mungkin berakhir dengan:

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) || []);

David Tang
sumber
Ini secara teknis jawaban yang lebih baik karena akan mengambil semua teks dari string yang tidak habis dibagi 3 (itu akan mengambil 2 atau 1 karakter terakhir).
Erik
6
Gunakan [\s\S]alih-alih .agar tidak gagal di baris baru.
Mike Samuel
2
Anda mungkin ingin memulai siklus baru di setiap baris. Jika Anda benar-benar memiliki baris baru, mereka mungkin mengindikasikan beberapa jenis transisi. str.match (/. {1,3} / gm) mungkin merupakan pilihan yang lebih baik.
kennebec
+1 Hati-hati: ''.match(/.{1,3}/g) dan ''.match(/.{3}/g)kembali nullsebagai ganti array kosong.
Web_Designer
4
Apakah mungkin untuk memiliki variabel di tempat nomor 3?
Ana Claudia
46

Jika Anda tidak ingin menggunakan ekspresi reguler ...

var chunks = [];

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

jsFiddle .

... kalau tidak solusi regex cukup bagus :)

alex
sumber
1
1 cos Saya lebih suka ini jika 3variabel seperti yang disarankan oleh OP. Ini lebih mudah dibaca daripada menggabungkan string regexp.
David Tang
kalau saja Anda bisa membungkusnya menjadi fungsi yang berguna siap digunakan
mmm
1
Ini lebih dari 10x lebih cepat dari opsi regex, jadi saya akan menggunakan ini (di dalam fungsi) jsbench.github.io/#9cb819bf1ce429575f8535a211f72d5a
Job
1
Pernyataan saya sebelumnya berlaku untuk Chromium (juga, saya sudah terlambat dengan mengedit komentar sebelumnya maka yang baru). Di Firefox saat ini "hanya" 30% lebih cepat di komputer saya, tapi itu masih lebih baik secara konsisten.
Pekerjaan
Apakah ini bisa bertahan lama?
Jacob Schneider
22
str.match(/.{3}/g); // => ['abc', 'def', 'ghi', 'jkl']
maerics
sumber
Ini berfungsi untuk 3saya tetapi kembali nulldengan 250. 🤔
Jim
9

Membangun jawaban sebelumnya untuk pertanyaan ini; fungsi berikut akan membagi string ( str) n-number ( size) karakter.

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>

Tuan Polywhirl
sumber
2

Solusi saya (sintaks ES6):

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

Kami bahkan dapat membuat fungsi dengan ini:

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

Kemudian Anda dapat memanggil fungsi dengan mudah dengan cara yang dapat digunakan kembali:

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

Bersulang

Jesus Gonzalez
sumber
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, []);

Solusi bersih tanpa REGEX

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

Fungsi di atas adalah apa yang saya gunakan untuk Base64 chunking. Itu akan membuat satu baris 75 karakter.

Dave Brown
sumber
Bisa juga dilakukan replace(/.{1,75}/g, '$&\n').
alex
1

Di sini kita menyelingi string dengan string lain setiap n karakter:

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;

};

jika kita menggunakan cara di atas seperti ini:

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

kita mendapatkan:

aag | aag | aeg | eag | e

dan di sini kita melakukan hal yang sama, tetapi dorong ke 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;

};

dan kemudian jalankan:

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

kita mendapatkan:

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

jika seseorang mengetahui cara untuk menyederhanakan kode di atas, lmk, tetapi harus berfungsi dengan baik untuk string.

Alexander Mills
sumber
cuplikan pertama Anda tidak berfungsi seperti yang diharapkan. Saya dimodifikasi di sini: jsfiddle.net/omarojo/ksvx2txb/261
omarojo
0

Beberapa solusi bersih tanpa menggunakan ekspresi reguler:

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

Contoh penggunaan - https://jsfiddle.net/maciejsikora/b6xppj4q/ .

Saya juga mencoba membandingkan solusi saya dengan regexp yang dipilih sebagai jawaban yang benar. Beberapa tes dapat ditemukan di jsfiddle - https://jsfiddle.net/maciejsikora/2envahrk/ . Pengujian menunjukkan bahwa kedua metode memiliki kinerja yang sama, mungkin pada solusi regexp tampilan pertama sedikit lebih cepat, tetapi menilai sendiri.

Maciej Sikora
sumber
0

Dengan .split:

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

dan .replaceakan:

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



/(?!$)/adalah untuk berhenti sebelum akhir /$/, tanpa adalah:

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

mengabaikan grup /(?:... )/tidak perlu di .replacetetapi di .splitmenambahkan grup ke arr:

var arr = str.split( /(?<=^(.{3})+)(?!$)/ )  // [ 'abc', 'abc', 'def', 'abc', 'ghi', 'abc', 'jkl' ]
Денис Дечев
sumber
0

Berikut cara untuk melakukannya tanpa ekspresi reguler atau loop eksplisit, meskipun sedikit memperluas definisi liner:

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

Ini bekerja dengan memisahkan string menjadi array karakter individu, lalu gunakan Array.reduceuntuk beralih ke setiap karakter. Biasanya reduceakan mengembalikan nilai tunggal, tetapi dalam kasus ini nilai tunggal terjadi menjadi array, dan ketika kami melewati setiap karakter kita menambahkannya ke item terakhir dalam array itu. Setelah item terakhir dalam array mencapai panjang target, kami menambahkan item array baru.

Malvine
sumber
0

Beberapa saat kemudian untuk diskusi tetapi di sini variasi yang sedikit lebih cepat daripada dorongan substring + array.

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

Pra-menghitung nilai akhir sebagai bagian dari for loop lebih cepat daripada melakukan inline math di dalam substring. Saya sudah mengujinya di Firefox dan Chrome dan keduanya menunjukkan peningkatan.

Anda bisa mencobanya di sini

Dragonaire
sumber