指定した文字の最初のインスタンスでのみ文字列を分割する


271

私のコード_では、配列に基づいて文字列を分割し、2番目の項目を取得します。

var element = $(this).attr('class');
var field = element.split('_')[1];

を受け取りgood_luck、私に提供しluckます。よく働く!

しかし、今はのようなクラスがありますgood_luck_buddy。javascriptに2番目のエラーを無視さ_せてくれluck_buddyますか?

私はこれvar field = element.split(new char [] {'_'}, 2);をac#stackoverflow回答で見つけましたが、機能しません。jsFiddleで試してみました...

回答:


407

括弧を使用する

"good_luck_buddy".split(/_(.+)/)[1]
"luck_buddy"

それらは次のように定義されます

separatorキャプチャ括弧が含まれている場合、一致した結果が配列で返されます。

したがって、この場合には、私たちは時分割したい_.+(つまり、スプリットセパレータは、サブ文字列で始まるもの_だけでなく、結果は私たちのセパレータの一部(すなわち含ませて、すべての後に_)。

この例では、セパレータ(一致_(.+))はで_luck_buddy、キャプチャされたグループ(セパレータ内)はlucky_buddyです。括弧をキャプチャしないと、luck_buddy(一致する.+)は結果の配列に含まれません。これは、splitセパレーターが結果に含まれないという単純な場合と同じであるためです。


21
あなたも必要としない、ちょうど1つのより多くの文字の最初の_後のキャプチャに/_(.+)/使い(?)
マーク

3
とてもエレガント。魅力のように機能します。ありがとうございました。
Ofeargall

12
明確にするために、このソリューションが機能する理由は、1番目以降のすべて_がキャプチャグループ内で一致し、その理由でトークンリストに追加されるためです。
アランムーア

28
誰もがなぜ私がこれで余分な空の文字列要素を取得するのか知っています:in:"Aspect Ratio: 16:9".split(/:(.+)/)out:["Aspect Ratio", " 16:9", ""]
katy lavallee

4
@katylavallee-これは役立つかもしれません:stackoverflow.com/questions/12836062/…セパレーターはなので、セパレーターの": 16:9"後に何もないため、最後に空の文字列が作成されます。
デレク━會功夫2014年

232

何のために正規表現と配列が必要ですか?

myString = myString.substring(myString.indexOf('_')+1)

var myString= "hello_there_how_are_you"
myString = myString.substring(myString.indexOf('_')+1)
console.log(myString)


5
string!==文字列。JavaScriptは大文字と小文字を区別します。
kennebec

3
これが最良の答えだと思います。第二の後の文字列を取得することも可能である_執筆者:myString.substring( myString.indexOf('_', myString().indexOf('_') + 1) + 1 )
muratgozel

9
答えは文字列の2番目の部分を出力します。最初の部分も欲しい場合はどうしますか?ではvar str = "good_luck_buddy", res = str.split(/_(.+)/);、あなたのすべての部品を得る:console.log(res[0]); console.log(res[1]);

1
@PeterLeger let split = [ string.substring(0, string.indexOf(options.divider)), string.substring(string.indexOf(options.divider) + 1) ]そこにあります。また、可変針のサポートあり
Steffan 2017年

これは天才です!
stuckedoverflow

36

RegExpは絶対に避けます。ここにあなたができるもう一つのことがあります:

"good_luck_buddy".split('_').slice(1).join('_')

18
RegExpを恐れている人は、RegExpの素晴らしさを決して知ることはできません。ドアを自分で見つける必要があります。一度そこに着くと、決して振り返ることはありません。数年後にもう一度私に尋ねてください。そうすれば、それがどれほど素晴らしいかをメに教えてくれます。
Christiaan Westerbeek、

3
@yonas赤い錠剤を飲みなさい!
frnhr 2015年

2
@yonasええ、赤い錠剤を飲んでください!短い文字列であっても、あなたの人生をより速くします:jsperf.com/split-by-first-colon
Julian F. Weinert

15
ハ!このコメントは4年以上前に書きました。私は間違いなくRegExpに参加しています!:)
yonas

3
@yonasのほうがいいです。あなたがそれを必要とするとき、RegExpは素晴らしいです。ここではそうではありません。更新されたテストを確認する:jsperf.com/split-by-first-colon/2
metalim

11

最初のインスタンスを一意のプレースホルダーに置き換え、そこから分割します。

"good_luck_buddy".replace(/\_/,'&').split('&')

["good","luck_buddy"]

これは、分割の両側が必要な場合により便利です。


3
これにより、文字列に不要な制約が課されます。
Yan Foto

上記のすべての回答がうまくいかなかったときに、この答えは私にとってうまくいきました。
GuitarViking 2017

1
@YanFotoは「&」を使用して意味しますか?それは何でもかまいません。
sebjwallace 2017

2
@sebjwallace何を選択しても、文字列にその文字を含めることはできません。例えば、 "fish&chips_are_great"は[fish、chips、are_great]を与えると思います。
Joe

@Joe「&」の代わりに何でも使用できます-これは単なる例です。必要に応じて、最初に出現する_を¬に置き換えることができます。したがって、「fish&chips_are_great」は、最初の_をwithに置き換えて「fish&chips¬are_great」を取得し、次に¬で分割して["fish&chips"、 "are_great"]を
取得し

8

次のような正規表現を使用できます。

var arr = element.split(/_(.*)/)
分割の制限を指定する2番目のパラメーターを使用できます。つまり、var field = element.split( '_'、1)[1];

6
これは、返される分割アイテムの数を指定するだけで、分割回数は指定しません。'good_luck_buddy'.split('_', 1);ちょうど返します['good']
Alex Vidal

ありがとうございます。正規表現を使用するように投稿を更新しました。
Chandu

(:?.*)非捕獲グループになるはずでしたか?もしそうなら、それはであるはずですが(?:.*)、それを修正すると、それはもはや機能しないことがわかります。 (:?.*)オプションの:後に0個以上の任意の文字が続くと一致します。このソリューションは、@ MarkFが行うのと同じ理由で最終的に機能し_ます。キャプチャグループで一致したため、1番目以降のすべてがトークンリストに追加されます。(また、このg修飾子は分割正規表現で使用した場合は効果がありません。)
アランムーア

ありがとう、気づかなかった。正規表現を更新して、いくつかのシナリオで試してみました...
Chandu

1
ie8では機能せず、indexOfおよびsubstringに切り替えます
Igor Alekseev

6

この解決策は私のために働いた

var str = "good_luck_buddy";
var index = str.indexOf('_');
var arr = [str.slice(0, index), str.slice(index + 1)];

//arr[0] = "good"
//arr[1] = "luck_buddy"

または

var str = "good_luck_buddy";
var index = str.indexOf('_');
var [first, second] = [str.slice(0, index), str.slice(index + 1)];

//first = "good"
//second = "luck_buddy"

1
ただし、スプリッターに複数の文字がある場合は機能しません。
haykam

5

今日でString.prototype.splitは実際に分割数を制限することができます。

str.split([separator[, limit]])

...

制限オプション

分割数を制限する負でない整数。指定した場合、指定したセパレーターが出現するたびに文字列を分割しますが、配列に制限エントリが配置されると停止します。残りのテキストは配列にまったく含まれません。

制限に達する前に文字列の終わりに達した場合、配列に含まれるエントリは制限よりも少ない場合があります。limitが0の場合、分割は実行されません。

警告

期待どおりに動作しない可能性があります。残りの区切り文字を単に無視することを望んでいましたが、代わりに、制限に達すると、残りの文字列を再度分割し、分割後の部分を戻り結果から省略します。

let str = 'A_B_C_D_E'
const limit_2 = str.split('_', 2)
limit_2
(2) ["A", "B"]
const limit_3 = str.split('_', 3)
limit_3
(3) ["A", "B", "C"]

私は期待していました:

let str = 'A_B_C_D_E'
const limit_2 = str.split('_', 2)
limit_2
(2) ["A", "B_C_D_E"]
const limit_3 = str.split('_', 3)
limit_3
(3) ["A", "B", "C_D_E"]

こっちも一緒。PHPが「最初」と「残り」に分かれているようです。
BananaAcid

4

String.split残念ながら、JavaScriptには実際の分割数を制限する方法がありません。これには、返される実際の分割項目の数を指定する2番目の引数がありますが、この場合は役に立ちません。解決策は、文字列を分割し、最初の項目をオフにシフトしてから、残りの項目を再結合することです::

var element = $(this).attr('class');
var parts = element.split('_');

parts.shift(); // removes the first item from the array
var field = parts.join('_');

split関数は役に立たないようですが、正規表現を使用するとこれが達成されるようです。Split関数自体をネイティブで参照していることを指定する必要があります。
Dan Hanly、2012

1
興味深いことに、このソリューションは、問題をより読みやすく管理しやすいソリューションにまで蒸留します。私のフルネームを姓と名に変換する場合(そうすることで要件がこのロジックを強制しました)、このソリューションは最も効果的で、他のソリューションより読みやすくなりました。ありがとう
スキマ

これはもう本当ではありません:)
クラーケン

3

文字列の2つの部分が必要なので、正規表現後読みがこれに役立ちます。

const full_name = 'Maria do Bairro';
const [first_name, last_name] = full_name.split(/(?<=^[^ ]+) /);
console.log(first_name);
console.log(last_name);


3

割り当てを分解することで、より読みやすくなります。

let [first, ...rest] = "good_luck_buddy".split('_')
rest = rest.join('_')

2

最速のソリューション?

私はいくつかのベンチマークを実行しましたが、このソリューションは大成功しました:1

str.slice(str.indexOf(delim) + delim.length)

// as function
function gobbleStart(str, delim) {
    return str.slice(str.indexOf(delim) + delim.length);
}

// as polyfill
String.prototype.gobbleStart = function(delim) {
    return this.slice(this.indexOf(delim) + delim.length);
};

他のソリューションとのパフォーマンス比較

substr代わりにを使用することを除いて、唯一の近い候補は同じコード行でしたslice

私は関与しようとした他のソリューションsplitまたはRegExpsが大きなパフォーマンスヒットを取り、2程度だった桁違いに遅いです。もちろん、のjoin結果を使用すると、splitパフォーマンスがさらに低下します。

なぜ遅いのですか?新しいオブジェクトまたは配列を作成する必要があるときはいつでも、JSはOSからメモリのチャンクを要求する必要があります。このプロセスは非常に遅いです。

ベンチマークを追跡する場合の一般的なガイドラインを次に示します。

  • オブジェクト{}または配列[]split作成するものなど)の新しい動的メモリ割り当ては、パフォーマンスに多くのコストがかかります。
  • RegExp 検索はより複雑であるため、文字列検索よりも時間がかかります。
  • すでに配列がある場合、配列の分解は明示的に配列にインデックスを付けるのと同じくらい速く、見栄えが良いです。

最初のインスタンスを超えて削除

以下は、n番目のインスタンスまでスライスするソリューションです。それほど速くはありませんが、OPの質問でgobble(element, '_', 1)は、RegExpまたはsplitソリューションよりも2倍以上高速であり、さらに多くのことができます。

/*
`gobble`, given a positive, non-zero `limit`, deletes
characters from the beginning of `haystack` until `needle` has
been encountered and deleted `limit` times or no more instances
of `needle` exist; then it returns what remains. If `limit` is
zero or negative, delete from the beginning only until `-(limit)`
occurrences or less of `needle` remain.
*/
function gobble(haystack, needle, limit = 0) {
  let remain = limit;
  if (limit <= 0) { // set remain to count of delim - num to leave
    let i = 0;
    while (i < haystack.length) {
      const found = haystack.indexOf(needle, i);
      if (found === -1) {
        break;
      }
      remain++;
      i = found + needle.length;
    }
  }

  let i = 0;
  while (remain > 0) {
    const found = haystack.indexOf(needle, i);
    if (found === -1) {
      break;
    }
    remain--;
    i = found + needle.length;
  }
  return haystack.slice(i);
}

上記の定義でgobble('path/to/file.txt', '/')は、ファイルの名前を指定し、gobble('prefix_category_item', '_', 1)この回答の最初のソリューションのように接頭辞を削除します。


  1. テストは、macOSX 10.14上のChrome 70.0.3538.110で実行されました。

さあ...それは2019年です...そこにいる人々は本当にこの種のものを本当にマイクロベンチマークしていますか?
VictorSchröder19年

同意する。マイクロベンチマークは少し興味深いですが、最適化についてはコンパイラーまたはトランスレーターに依存する必要があります。これを読んでいる誰かがコンパイラを構築しているか、ejs / embeddedを使用しており、正規表現を使用できません。ただし、これは正規表現よりも私の特定のケースに適しています。(「最速の解決策」を削除します)
TamusJRoyce

1

Mark Fのソリューションは素晴らしいですが、古いブラウザではサポートされていません。Kennebecのソリューションは素晴らしく、古いブラウザでサポートされていますが、正規表現はサポートしていません。

したがって、文字列を1回だけ分割するソリューションを探している場合、それは古いブラウザでサポートされ、正規表現をサポートしています。これが私のソリューションです。

String.prototype.splitOnce = function(regex)
{
    var match = this.match(regex);
    if(match)
    {
        var match_i = this.indexOf(match[0]);
        
        return [this.substring(0, match_i),
        this.substring(match_i + match[0].length)];
    }
    else
    { return [this, ""]; }
}

var str = "something/////another thing///again";

alert(str.splitOnce(/\/+/)[1]);


1

正規表現に慣れていない私のような初心者にとって、この回避策のソリューションはうまくいきました:

   var field = "Good_Luck_Buddy";
   var newString = field.slice( field.indexOf("_")+1 );

slice()メソッドは文字列の一部を抽出して新しい文字列を返し、indexOf()メソッドは文字列内で指定された値が最初に見つかった位置を返します。


これは回避策ではありませんが、適切な方法です;)
VictorSchröder19年

1

正規表現で string replace()メソッドを使用します。

var result = "good_luck_buddy".replace(/.*?_/, "");
console.log(result);

この正規表現は、最初のの前の0個以上の文字_、および_それ自体と一致します。その後、一致は空の文字列に置き換えられます。


document.body.innerHTMLここの部分は完全に役に立たない。
VictorSchröder19年

@VictorSchröderなしでスニペットの出力をどのように期待しますdocument.body.innerHTMLか?
James T

2
document.body存在するDOMに依存し、純粋なJavaScript環境では機能しません。console.logこの目的のために十分であるか、単に検査のために結果を変数に残します。
VictorSchröder19年

@VictorSchröder混乱を招いたとは思いませんが、それでも編集しました。
James T

0

これは私にとってChrome + FFでうまくいきました:

"foo=bar=beer".split(/^[^=]+=/)[1] // "bar=beer"
"foo==".split(/^[^=]+=/)[1] // "="
"foo=".split(/^[^=]+=/)[1] // ""
"foo".split(/^[^=]+=/)[1] // undefined

キーも必要な場合は、これを試してください:

"foo=bar=beer".split(/^([^=]+)=/) // Array [ "", "foo", "bar=beer" ]
"foo==".split(/^([^=]+)=/) // [ "", "foo", "=" ]
"foo=".split(/^([^=]+)=/) // [ "", "foo", "" ]
"foo".split(/^([^=]+)=/) // [ "foo" ]

//[0] = ignored (holds the string when there's no =, empty otherwise)
//[1] = hold the key (if any)
//[2] = hold the value (if any)

0

トリックを行う1つのRegExpを次に示します。

'good_luck_buddy' . split(/^.*?_/)[1] 

最初に、 '^'で始まる最初からマッチを強制します。次に、「_」以外の任意の数の文字、つまり最初の「_」より前のすべての文字に一致します。

「?」パターン全体を一致させる最小数の文字が「。*?」で一致することを意味します '_'が後に続き、最後の文字として一致に含まれます。

したがって、このsplit()は一致する部分を「スプリッター」として使用し、結果から削除します。したがって、最初の「_」までのすべてを削除し、残りを結果の2番目の要素として提供します。最初の要素は ""で、一致したパーツの前のパーツを表します。試合は最初から始まるので「」です。

以前の回答でChanduによって与えられた/_(.*)/のように機能する他のRegExpがあります。

/^.*?_/には、replace()でグループをキャプチャする特別な役割を知らなくても、その機能を理解できるという利点があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.