Javascriptとregex:文字列を分割し、セパレータを保持する


130

文字列があります:

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

そして、この文字列を区切り文字と<br />その後に続く特殊文字で分割したいと思います。

それをするために、私はこれを使用しています:

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

区切り文字がなくなったことを除いて、必要なものを取得しています。次に例を示します。http//jsfiddle.net/JwrZ6/1/

区切り文字を保持するにはどうすればよいですか?


あなたが事前に区切り文字を知っていれば、その理由だけでありませんか... var delim = "<br/>";
Andreas Wong

@SiGantengに感謝します。事前に区切り文字を知っていますが、私の例では機能しません。区切り文字を<br />の後に特殊文字が続くようにする必要があります。特殊文字が<br />の後に続かないことがあり、これを分割する必要がない場合があるためです。
ミロシュ

2
良い質問ですが、区切り文字を知っていても役に立たないという同様のケースがあります。「]&[」で分割しています。したがって、実際の区切り文字は "&"ですが、その分割は十分正確ではありません。適切な分割を決定するには、角かっこを両側に配置する必要があります。ただし、分割した文字列にこれらの角かっこが必要です。両側に1つずつ。
PandaWood 2014年

回答:


103

使用(正)は、先読み正規表現の特殊文字が存在すると主張しているが、実際には一致しないように:

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

実際に見てください:

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


このコードを使用すると0、各文字列の末尾にaが追加されます
keyboard-warrior

2
私はあなたが与えたリンクで前向きな先読みについて何も見つけることができません。
ポールクリスジョーンズ

@PaulJonesコンテンツはその間に移動されました。お知らせいただきありがとうございます。リンクを修正しました。
ジョン

178

似たような問題が少しありました。とにかく、ここに、排泄物を保管する場所の3つの異なるシナリオの例を示します。

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

警告: 4番目は単一の文字を分割する場合にのみ機能します。ConnorsFan代替を提示します

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

3
私は3番目の例のようなものを探していましたが、これは要素が1文字のみの場合にのみ機能します。それ以外の場合は個別の文字に分割されます。結局、退屈なRegExp.execルートに行かなければなりませんでした。
Gordon

2
誰もが/ gを使用している理由がわかりません
Sarsaparilla '11年

1
この正規表現 "1、2、3" .split(/(?!、)/ g)== ["1、"、 "2、"、 "3"]を完全な単語にどのように使用しますか?たとえば、 "foo1、foo2、foo3、"
Waltari

あなたは天才です!あなたはそれがどのように機能するかを説明するドキュメントをどこで見つけますか?g終わりは必要ありません
ペリー・ミモン

1
.matchこれらの例の貪欲でない解決策の翻訳: "11、22、33".match(/.*?、|.+$/g)-> ["11、", "22、", "33"]。Note /gモディファイアはマッチに不可欠です。
Beni Cherniavsky-Paskin

57

区切り文字を括弧で囲んだ場合は、返される配列の一部になります。

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

保持する部分に応じて、一致するサブグループを変更します

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

文字の大文字と小文字を無視することで式を改善できますstring.split(/()&#?[a-z0-9] +; / gi);

そして、あなたは、このような事前定義されたグループのために一致させることができます:\d等しい[0-9]\w等しいです[a-zA-Z0-9_]。つまり、式は次のようになります。

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

JavaScriptKitには、優れた正規表現リファレンスがあります


4
さらに良いことに、区切り文字の一部しか保持できないことはわかりません。実際、私は特別な文字だけを保持する必要があります。これでこれを行うことができます:string.split(/ <br \/>(&#?[a-zA-Z0-9] +;)/ g);
ミロシュ

1
単語の大文字小文字を無視することで、表現を最適化できます。または、事前定義された文字クラスに一致します。回答を更新します。
Torsten Walter

2
なぜこれがそれほど低いのでしょうか?その完璧で柔軟性
Tofandel '22

2
これは確かに最も簡単な方法であり、最も読みやすい構文です。
Timar Ivo Batis

4

ここでも答えた JavaScript分割正規表現区切り文字を保持する

正規表現の例で(?= pattern)先読みパターンを使用する

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

これにより、次の結果が得られます。

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

直接分割することもできます

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

同じ結果を与える

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

ジョンの受け入れられた回答のように、すぐに分割しないのはなぜですか?
Gordon

@Gordon ... :)私はそれを行うことができます...コードを更新しました... Cheers
Fry

1

拡張関数は文字列を部分文字列またはRegExで分割し、区切り文字は2番目のパラメーターに従って前後に配置されます。

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

テスト:

    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

jichiの答えを修正し、複数文字にも対応する関数に入れました。

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

jichiの回答3番目の方法はこの関数では機能しないので、4番目の方法を採用し、空のスペースを削除して同じ結果を得ました。

編集:char1またはchar2を分割する配列を除く2番目のメソッド

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

使用法:

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

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

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

0

私はこれを使ってきました:

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

をいじってはいけないことを除いてString.prototype、関数バージョンは次のとおりです。

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

だからあなたはできる:

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

そして、あなたは次のようになります:

[
  "<br />&dagger; bbbb",
  "<br />&Dagger; cccc"
]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.