Javascript và regex: tách chuỗi và giữ dấu phân cách


130

Tôi có một chuỗi:

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

Và tôi muốn chia chuỗi này với dấu phân cách <br />theo sau là một ký tự đặc biệt.

Để làm điều đó, tôi đang sử dụng điều này:

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

Tôi đang nhận được những gì tôi cần, ngoại trừ việc tôi đang mất dấu phân cách. Dưới đây là ví dụ: http://jsfiddle.net/JwrZ6/1/

Làm thế nào tôi có thể giữ dấu phân cách?


nếu bạn biết trước dấu phân cách, tại sao không làm ... var delim = "<br/>";?
Andreas Wong

Cảm ơn bạn @SiGanteng, tôi biết dấu phân cách trước nhưng tôi không thể làm cho nó hoạt động cho ví dụ của mình. Tôi cần phải giữ dấu phân cách là <br /> theo sau là ký tự đặc biệt bởi vì đôi khi tôi có thể có một <br /> không được theo sau bởi char đặc biệt và cái này không phải bị tách ra.
Miloš

2
Câu hỏi hay, tôi có một trường hợp tương tự khi biết dấu phân cách không giúp ích. Tôi đang chia tách "] & [". Vì vậy, thực sự dấu phân cách của tôi là "&" nhưng phân tách trên đó không đủ chính xác, tôi cần lấy dấu ngoặc ở hai bên để xác định phân tách thích hợp. Tuy nhiên, tôi cần những dấu ngoặc đó trở lại trong chuỗi phân tách của tôi. 1 trong mỗi, hai bên.
PandaWood

Câu trả lời:


103

Sử dụng giao diện (tích cực) để biểu thức chính quy khẳng định rằng ký tự đặc biệt tồn tại, nhưng không thực sự khớp với nó:

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

Xem nó trong hành động:

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


Khi tôi sử dụng mã này, nó sẽ thêm 0vào cuối mỗi chuỗi
chiến binh bàn phím

2
Tôi không thể tìm thấy bất cứ điều gì về cái nhìn tích cực trong liên kết bạn đã đưa ra.
Paul Chris Jones

@PaulJones nội dung đã được di chuyển trong thời gian can thiệp. Cảm ơn đã cho tôi biết, tôi đã sửa liên kết.
Jon

178

Tôi đã có vấn đề tương tự nhưng hơi khác nhau. Dù sao, đây là ví dụ về ba kịch bản khác nhau về nơi giữ dấu phân cách.

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

Cảnh báo: Thứ tư sẽ chỉ hoạt động để phân chia các ký tự đơn. ConnorsFan trình bày một thay thế :

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

3
Tôi đã tìm kiếm một cái gì đó giống như ví dụ thứ ba, nhưng điều này chỉ hoạt động nếu các yếu tố chỉ có một ký tự - nó sẽ phân chia thành các ký tự riêng lẻ. Cuối cùng tôi đã phải đi theo con đường RegExp.exec tẻ nhạt .
Gordon

2
Tôi không hiểu tại sao mọi người lại sử dụng / g
Sarsaparilla

1
Làm thế nào sẽ sử dụng regex này "1、2、3" .split (/ (?!) / G) == ["1 、", "2 、", "3"] cho các từ đầy đủ? Ví dụ: "foo1, foo2, foo3"
Waltari

Bạn là một thiên tài!. nơi bạn tìm thấy tài liệu giải thích cách thức hoạt động? bạn không cần gkết thúc
pery mimon

1
Bản dịch của .matchgiải pháp không tham lam cho các ví dụ này: "11、22、33".match(/.*?、|.+$/g)-> ["11、", "22、", "33"]. Lưu ý /gsửa đổi là rất quan trọng cho trận đấu.
Beni Cherniavsky-Paskin

57

Nếu bạn bọc dấu phân cách trong parantheses, nó sẽ là một phần của mảng được trả về.

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

Tùy thuộc vào phần nào bạn muốn tiếp tục thay đổi nhóm con nào phù hợp với bạn

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

Bạn có thể cải thiện biểu thức bằng cách bỏ qua trường hợp ký tự chuỗi.split (/ () & #? [A-z0-9] +; / gi);

Và bạn có thể kết hợp cho các nhóm được xác định trước như thế này: \dbằng [0-9]\wbằng [a-zA-Z0-9_]. Điều này có nghĩa là biểu hiện của bạn có thể trông như thế này.

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

Có một tài liệu tham khảo biểu thức chính quy tốt trên JavaScriptKit .


4
Thậm chí tốt hơn, tôi không biết rằng chúng ta chỉ có thể giữ một phần của dấu phân cách. Trong thực tế tôi chỉ cần giữ char đặc biệt, tôi có thể làm điều đó với điều này: string.split (/ <br \/> (& #? [A-zA-Z0-9] +;) / g);
Miloš

1
Bạn có thể tối ưu hóa biểu thức của mình bằng cách bỏ qua trường hợp từ. Hoặc phù hợp cho một lớp nhân vật được xác định trước. Tôi sẽ cập nhật câu trả lời của tôi.
Torsten Walter

2
Tại sao điều này quá thấp .. Nó hoàn hảo và linh hoạt
Tofandel

2
Đây chắc chắn là cách dễ nhất và cú pháp dễ đọc nhất.
Timar Ivo Batis

4

đã trả lời nó ở đây cũng JavaScript Chia biểu thức chính quy giữ dấu phân cách

sử dụng mẫu lookahead (? = mẫu) trong ví dụ regex

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

Điều này sẽ cung cấp cho bạn kết quả sau đây.

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

Cũng có thể được chia trực tiếp

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

cho kết quả tương tự

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

Tại sao không ngay lập tức tách ra, như trong câu trả lời được chấp nhận của Jon?
Gordon

@Gordon ... :) Tôi chỉ có thể làm điều đó ... đã cập nhật mã ... Chúc mừng
Fry

1

Hàm mở rộng sẽ phân tách chuỗi với chuỗi con hoặc RegEx và dấu phân cách được cắt theo tham số thứ hai trước hoặc sau.

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

Các bài kiểm tra:

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

1

Tôi đã sửa đổi câu trả lời của jichi và đưa nó vào một chức năng cũng hỗ trợ nhiều chữ cái.

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

Câu trả lời của jichi Phương thức thứ 3 sẽ không hoạt động trong chức năng này, vì vậy tôi đã sử dụng phương pháp thứ 4 và xóa các khoảng trống để có kết quả tương tự.

chỉnh sửa: phương thức thứ hai chấp nhận một mảng để tách char1 hoặc 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);
    }
};

sử dụng:

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

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

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

0

Tôi đã sử dụng cái này:

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

Ngoại trừ việc bạn không nên gây rối String.prototype, vì vậy đây là phiên bản chức năng:

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

Vì vậy, bạn có thể làm:

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

Và bạn sẽ kết thúc với:

[
  "<br />&dagger; bbbb",
  "<br />&Dagger; cccc"
]
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.