結果の配列を切り捨てるのではなく、.split()が分割する時間を制限する

Limiting the times that .split() splits, rather than truncating the resulting array


質問 written by Nic Hartley @2015-05-02 11:48:09Z

: 7 : 6 : 1

本当に、ほとんどタイトルが言っていること。

この文字列があるとします:

var theString = "a=b=c=d";

さて、 theString.split("=")を実行すると、結果は予想どおり["a", "b", "c", "d"]ます。 そして、もちろん、 theString.split("=", 2)実行すると、 ["a", "b"]が得られます。これは、 String#split() MDNページを読んだ後に意味をなします。

ただし、私が探している動作はJavaのString#split()似ています:通常の配列を構築してから最初のn個の要素を返す代わりに、最初のn-1個の一致の配列を構築し、残りのすべてを追加します配列の最後の要素としての文字。 より適切な説明については、関連ドキュメントを参照してください。

Javascriptでこの効果を得るにはどうすればよいですか?

Javaの実装のように機能する最高のパフォーマンスを備えた答えを探していますが、実際の動作は異なる場合があります。

私は自分の試みを投稿しますが、これを書く方法についてはまったく知りません。

コメント 1

これを実装するための非常に簡単な1行のes6コードがあると思いましたか?

written by フアン @2018-06-13 08:12:42Z

回答 1 written by Asad Saeeduddin @2017-07-18 11:10:03Z
6

Java実装とまったく同じものが必要な場合(エラーチェックやガード句などは不要):

function split(str, sep, n) {
    var out = [];

    while(n--) out.push(str.slice(sep.lastIndex, sep.exec(str).index));

    out.push(str.slice(sep.lastIndex));
    return out;
}

console.log(split("a=b=c=d", /=/g, 2)); // ['a', 'b', 'c=d']

これには、質問で述べたように、事前に完全な分割を計算しないという追加の利点があります。

コメント 1

これがどのように機能するかの簡単な説明を追加できますか?

written by ニックハートリー @2015-05-02 04:50:00Z

コメント 2

@QPaysTaxes「limit」回数反復し、各反復でステートフル正規表現を使用して、次に出現する分割文字を見つけます。正規表現は、最後の一致がどこにあったかを記憶しており、一度実行すると、次の一致がどこにあるかがわかります。各反復でこれらの2つの場所の間に文字列スライスを追加します。ループの外側で、最後の正規表現の一致と文字列の最後の間に文字列スライスを追加します。

written by アサドSaeeduddin @2015-05-02 04:51:16Z

コメント 3

また、OPがパフォーマンスについて尋ねたため、この実装は(Chromeで)他の2倍の約2倍の速度です。驚いた!

written by -Sマクロハン @2015-05-02 04:59:36Z

コメント 4

@SMcCrohanそれは実に驚くべきことです。文字列と分割の数が漸近的に大きくなると、これはより良いパフォーマンスになると確信していましたが、JS正規表現の一定のオーバーヘッドは、小さな入力に対して他のものより遅くなると想定していました。

written by アサドSaeeduddin @2015-05-02 05:01:30Z

コメント 5

@Asad-はい、それは文字列に多数のセパレータがあるテスト用でした。入力文字列が非常に短い場合、部分文字列アプローチに遅れをとりましたが、それほど多くはありませんでした-14%。

written by -Sマックロハン @2015-05-02 05:09:35Z

回答 2 written by S McCrohan @2015-05-02 04:39:30Z
3

私は次のようなものを使用します:

function JavaSplit(string,separator,n) {
    var split = string.split(separator);
    if (split.length <= n)
        return split;
    var out = split.slice(0,n-1);
    out.push(split.slice(n-1).join(separator));
    return out;
}

ここで行っていることは:

  1. 文字列全体を分割する
  2. 説明したように、最初のn-1個の要素を取得します。
  3. 残りの要素を再結合します。
  4. それらをステップ2の配列に追加して戻ります。

これらの呼び出しをすべて連鎖させることが合理的に考えられるかもしれませんが、 .push()は新しい配列を返すのではなく配列を変更します。 また、この方法に従う方が少し簡単です。

コメント 1

こんにちは、多分あなたはスライスを行う前に分割結果の長さがnよりも大きいことを確認する必要があります。そうでなければ、単に分割結果を返します。

written by 確かに @2015-05-02 04:34:01Z

コメント 2

いい視点ね;追加されました。

written by -Sマクロハン @2015-05-02 04:39:41Z

コメント 3

私はこれがシンプルであることを気に入っていますが、(ベンチマークを行わずにわかる限り)より効率的であるため、もう一方を受け入れています。

written by ニックハートリー @2015-05-02 04:44:10Z

コメント 4

はい、そうです。どれだけそうだったかに興味があったので、簡単なjsperfを実行しました-約25%の差でした。

written by -Sマックロハン @2015-05-02 04:55:41Z

回答 3 written by Yauheni Leichanok @2015-05-02 04:48:50Z
2

もう1つの可能な実装:

function split(s, separator, limit) {
  // split the initial string using limit
  var arr = s.split(separator, limit);
  // get the rest of the string...
  var left = s.substring(arr.join(separator).length + separator.length);
  // and append it to the array
  arr.push(left);
  return arr;
}

フィドルはこちらです。

コメント 1

length + 1についてはよくわかりませんが、最後の要素に先頭のseparatorかどうかは、要件によって異なります。

written by -Yauheni Leichanok @2015-05-02 04:46:25Z

コメント 2

複数+separator.lengthを取得する場合は、 + 1+separator.length置き換えます。

written by -Sマックロハン @2015-05-02 04:46:27Z

回答 4 written by Felipe N Moura @2018-07-10 04:31:58Z
2

より少ない行でそれを行い、ループを避けたい場合:

const theString = "some=string=with=separators";
const limit = 2;
const parts = theString.split('=', limit);
parts.push(theString.slice(parts.join('').length + limit));
回答 5 written by Super Cat @2017-07-04 21:08:04Z
0

PHPのexplode近いものをお探しですか?

これが私が考案した方法です:

String.prototype.explode = function(sep, n) {
  var arr = this.split(sep, n)
  if (arr[n-1] != undefined) arr[n-1] += this.substring(arr.join(' ').length);
  return arr;
}

このメソッドは、通常のように文字列を分割し、限界に達したかどうかを判断し、 substringを使用して最後の分割を超えてテキストを追加します( join lengthを取得することにより、最後の分割を超える最初の文字のオフセットに直接アクセスできます)任意の1文字を区切り文字として配列で使用されます)

このメソッドはsplit同じように使用さsplitます:

This method is used just like split:

そしてもちろん、これは関数としてスピンすることもできます:

str = 'my/uri/needs/to/be/split';
splitResult = str.split('/', 4);
explodeResult = str.explode('/', 4);
console.log(splitResult);
console.log(explodeResult);

// The following will be written to the console:
// splitResult:   ["my", "uri", "needs", "to"]
// explodeResult: ["my", "uri", "needs", "to/be/split"]
回答 6 written by Gihan @2018-08-22 11:00:24Z
0

const theString = "a=b=c=d";
const [first, ...rest] = theString.split("=");
const second = rest.join("=")
console.log(first, second)

ECMA 2015を使用している場合、必要なのは2行だけです。

コメント 1

n > 1これはどのように機能しますか?または変数n

written by ニックハートリー @2018-08-22 19:50:44Z

コメント 2

変数nでは機能しません。しかし、既知のより小さいn

written by -Gihan @2018-08-23 05:06:29Z

回答 7 written by Tomer @2019-06-27 13:56:45Z
0

この私の実装:

String.prototype.splitRemainder = function(delim, count) {
	if (typeof delim !== 'string') {
		return this.split();    
	}

	if (typeof count !== 'number') {
		return this.split(delim);
	}

	if (count < 2) {
		return this.split(delim);
	}

	count--;
	const parts = this.split(delim, count);
	const remainder = this.slice(parts.join('').length + count);

	if (remainder.length > 0) {
		parts.push(remainder);
	}

	return parts;
}

console.log("dasd asds asds asdasd asdasdas".splitRemainder(" ", 4));
console.log("hello-to-you-too".splitRemainder("-",2));

それを実装する最も効率的な方法ではないことに注意してください。 したがって、最も効率的なソリューションを探しているなら、これはそうではありません。