Làm thế nào tôi có thể chia một chuỗi thành các phân đoạn của n ký tự?


200

Như tiêu đề đã nói, tôi đã có một chuỗi và tôi muốn chia thành các phân đoạn của n ký tự.

Ví dụ:

var str = 'abcdefghijkl';

sau một số phép thuật với n=3, nó sẽ trở thành

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

Có cách nào để làm việc này không?

Câu trả lời:


358

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

Lưu ý: Sử dụng {1,3}thay vì chỉ {3}để bao gồm phần còn lại cho độ dài chuỗi không phải là bội số của 3, ví dụ:

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


Một vài tinh tế hơn:

  1. Nếu chuỗi của bạn có thể chứa các dòng mới ( mà bạn muốn tính là một ký tự thay vì tách chuỗi ), thì chuỗi .sẽ không bắt được các dòng đó. Sử dụng /[\s\S]{1,3}/thay thế. (Cảm ơn @Mike).
  2. Nếu chuỗi của bạn trống, sau đó match()sẽ trả về nullkhi bạn có thể mong đợi một mảng trống. Bảo vệ chống lại điều này bằng cách nối thêm || [].

Vì vậy, bạn có thể kết thúc với:

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


Về mặt kỹ thuật, đây là câu trả lời tốt hơn vì nó sẽ lấy tất cả văn bản từ một chuỗi không chia hết cho 3 (nó sẽ lấy 2 hoặc 1 ký tự cuối cùng).
Erik

6
Sử dụng [\s\S]thay vì .để không thất bại trên dòng mới.
Mike Samuel

2
Bạn có thể muốn bắt đầu một chu kỳ mới trên mỗi dòng. Nếu bạn thực sự có dòng mới, chúng có thể chỉ ra một số loại chuyển đổi. str.match (/. {1,3} / gm) có thể là lựa chọn tốt hơn.
kennebec

+1 Cẩn thận: ''.match(/.{1,3}/g)''.match(/.{3}/g)trả về nullthay vì một mảng trống.
Web_Designer

4
Có thể có một biến ở vị trí số 3?
Ana Claudia

46

Nếu bạn không muốn sử dụng biểu thức chính quy ...

var chunks = [];

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

jsFiddle .

... nếu không thì giải pháp regex khá tốt :)


1
+1 cos Tôi thích điều này nếu 3biến được đề xuất bởi OP. Nó dễ đọc hơn nối chuỗi regrec.
David Tang

nếu chỉ bạn có thể gói nó thành một chức năng hữu ích sẵn sàng để sử dụng
mmm

1
Tốc độ này nhanh hơn gấp 10 lần so với tùy chọn regex, vì vậy tôi sẽ sử dụng tùy chọn này (bên trong hàm) jsbench.github.io/#9cb819bf1ce429575f8535a211f72d5a
Công việc

1
Tuyên bố trước đây của tôi áp dụng cho Chromium (đồng thời, tôi đã quá muộn với việc chỉnh sửa nhận xét trước đó do đó là nhận xét mới). Trên Firefox hiện tại "chỉ" nhanh hơn 30% trên máy của tôi, nhưng điều đó vẫn luôn tốt hơn.
Công việc

điều này có bền vững qua các chuỗi dài không?
Jacob Schneider

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

Điều này làm việc cho 3tôi nhưng trả lại nullvới 250. 🤔
Jim

9

Dựa trên các câu trả lời trước cho câu hỏi này; hàm sau sẽ phân tách một chuỗi ( str) n-number ( size) của các ký tự.

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

Bản giới thiệu

(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

Giải pháp của tôi (cú pháp ES6):

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

Chúng tôi thậm chí có thể tạo ra một chức năng với điều này:

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

Sau đó, bạn có thể gọi hàm dễ dàng theo cách có thể sử dụng lại:

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

Chúc mừng


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

Giải pháp sạch mà không cần REGEX


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

Chức năng trên là những gì tôi sử dụng cho chunking Base64. Nó sẽ tạo ra một ngắt dòng bao giờ 75 ký tự.


Cũng có thể làm replace(/.{1,75}/g, '$&\n').
alex

1

Ở đây chúng ta xen kẽ một chuỗi với một chuỗi khác mỗi n ký tự:

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;

};

nếu chúng ta sử dụng như trên:

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

chúng tôi nhận được:

aag | aag | aeg | eag | e

và ở đây chúng tôi làm tương tự, nhưng đẩy đến một mảng:

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;

};

và sau đó chạy nó:

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

chúng tôi nhận được:

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

nếu ai đó biết một cách để đơn giản hóa đoạn mã trên, lmk, nhưng nó sẽ hoạt động tốt cho các chuỗi.


đoạn đầu tiên của bạn không hoạt động như mong đợi. Tôi đã sửa đổi ở đây: jsfiddle.net/omarojo/ksvx2txb/261
omarojo

0

Một số giải pháp sạch mà không sử dụng biểu thức thông thường:

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

Ví dụ sử dụng - https://jsfiddle.net/maciejsikora/b6xppj4q/ .

Tôi cũng đã cố gắng so sánh giải pháp của mình với regrec một giải pháp được chọn là câu trả lời đúng. Một số thử nghiệm có thể được tìm thấy trên jsfiddle - https://jsfiddle.net/maciejsikora/2envahrk/ . Các thử nghiệm đang cho thấy rằng cả hai phương pháp đều có hiệu suất tương tự nhau, có thể trên giải pháp regrec nhìn đầu tiên nhanh hơn một chút, nhưng hãy tự đánh giá nó.


0

Với .split:

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

.replacesẽ là:

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



/(?!$)/là dừng lại trước khi kết thúc /$/, mà không có:

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

bỏ qua nhóm /(?:... )/là không cần trong .replacenhưng trong .splitviệc thêm các nhóm vào mảng:

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

0

Đây là một cách để làm điều đó mà không cần các biểu thức thông thường hoặc các vòng lặp rõ ràng, mặc dù nó kéo dài định nghĩa của một lớp lót một chút:

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

Nó hoạt động bằng cách chia chuỗi thành một mảng các ký tự riêng lẻ, sau đó sử dụng Array.reduceđể lặp qua từng ký tự. Thông thường reducesẽ trả về một giá trị duy nhất, nhưng trong trường hợp này, giá trị đơn lẻ là một mảng và khi chúng ta chuyển qua từng ký tự, chúng ta sẽ thêm nó vào mục cuối cùng trong mảng đó. Khi mục cuối cùng trong mảng đạt đến độ dài mục tiêu, chúng tôi sẽ thêm một mục mảng mới.


0

Đến một lúc sau để thảo luận nhưng ở đây một biến thể nhanh hơn một chút so với chuỗi con + mảng đẩy một.

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

Tính toán trước giá trị cuối như một phần của vòng lặp for nhanh hơn so với thực hiện phép toán nội tuyến bên trong chuỗi con. Tôi đã thử nghiệm nó trên cả Firefox và Chrome và cả hai đều hiển thị tốc độ.

Bạn có thể thử nó ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.