dizeyi yalnızca belirtilen karakterin ilk örneğinde böl


271

Kodumda bir dizeyi temel alarak _böldüm ve dizideki ikinci öğeyi yakaladım.

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

good_luckBeni alır ve sağlar luck. Harika çalışıyor!

Ama şimdi benzeyen bir sınıfım var good_luck_buddy. Javascript'imi ikinciyi görmezden gelip bana nasıl _verebilirim luck_buddy?

Bunu var field = element.split(new char [] {'_'}, 2);ac # stackoverflow yanıtında buldum ama çalışmıyor. Ben jsFiddle de denedim ...

Yanıtlar:


406

Yakalama parantezlerini kullanın :

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

Olarak tanımlanırlar

Eğer separatorparantez yakalayan içerir eşleşen sonuçlar dizide döndürülür.

Bu durumda, bölmek istiyoruz _.+(yani bölünmüş ayırıcı ile başlayan bir alt dize _) ama aynı zamanda sonucun ayırıcımızın bir kısmını (yani her şeyden sonra _) içermesine izin veriyoruz .

Bu örnekte ayırıcımız (eşleşen _(.+)) _luck_buddyve yakalanan grup (ayırıcı içinde) şeklindedir lucky_buddy. Yakalama parantezi olmasaydı, luck_buddy(eşleme .+) sonuç dizisine splitdahil edilmezdi, çünkü ayırıcıların sonuca dahil edilmemesi basittir .


21
Hatta ihtiyacınız yok (?), İlk _den sonra 1 karakter daha yakalamak için /_(.+)/ kullanın.
Mark

3
Çok zarif. Tıkır tıkır çalışıyor. Teşekkür ederim.
Ofeargall

12
Açık olmak gerekirse, bu çözümün çalışmasının nedeni, ilkinden sonraki her şeyin _bir yakalama grubu içinde eşleştirilmesi ve bu nedenle jeton listesine eklenmesi.
Alan Moore

28
Herkes neden bu ile ekstra boş bir dize elemanı almak biliyorum: içinde: "Aspect Ratio: 16:9".split(/:(.+)/)dışarı:["Aspect Ratio", " 16:9", ""]
katy lavallee

4
@katylavallee - Bu yardımcı olabilir: stackoverflow.com/questions/12836062/… Ayırıcı olduğundan ": 16:9", ayırıcıdan sonra hiçbir şey yoktur, böylece sonunda boş dize oluşturulur.
Derek 朕 會 功夫

232

Ne için düzenli ifadelere ve dizilere ihtiyacınız var?

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

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


5
string! == Dize. javascript büyük / küçük harfe duyarlıdır.
kennebec

3
bence bu en iyi cevap. ayrıca _yazarak ikinci sırada dize almak da mümkündür :myString.substring( myString.indexOf('_', myString().indexOf('_') + 1) + 1 )
muratgozel

9
Cevap dizenin ikinci kısmını verir. İlk bölümü de istiyorsanız? İle var str = "good_luck_buddy", res = str.split(/_(.+)/);size tüm parçaları almak:console.log(res[0]); console.log(res[1]);
Güneş

1
@PeterLeger let split = [ string.substring(0, string.indexOf(options.divider)), string.substring(string.indexOf(options.divider) + 1) ]İşte burada. Ayrıca değişken iğne desteği ile
Steffan

Bu Genius!
stuckedoverflow

36

Ben ne pahasına olursa olsun RegExp kaçının. İşte yapabileceğiniz başka bir şey:

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

18
RegExp'den korkan birine RegExp'in ne kadar harika olduğu asla söylenemez. Kapıyı kendin bulmalısın. Oraya vardığınızda, asla geriye bakmazsınız. Birkaç yıl sonra bana tekrar sorun ve bana ne kadar harika olduğunu anlatacaksınız.
Christiaan Westerbeek

3
@yonas Kırmızı hapı al!
frnhr

2
@yonas Evet, kırmızı hapı al! Kısa teller için bile hayatınızı hızlandıracak: jsperf.com/split-by-first-colon
Julian F. Weinert

15
Ha! Bu yorumu 4+ yıl önce yazdım. Ben kesinlikle RegExp ile gemide şimdi! :)
yonas

3
@yonas yapsan iyi edersin. RegExp ihtiyacınız olduğunda harika . Burada durum böyle değil. Güncelleme testini kontrol edin: jsperf.com/split-by-first-colon/2
metalim

11

İlk örneği benzersiz bir yer tutucuyla değiştirin, ardından oradan bölün.

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

["good","luck_buddy"]

Bölmenin her iki tarafı gerektiğinde bu daha yararlıdır.


3
Bu, dize gereksiz bir kısıtlama getirir.
Yan Foto

Yukarıdaki cevapların hepsi işe yaramadığında bu cevap benim için çalıştı.
GuitarViking

1
@YanFoto '&' kullanarak mı demek istiyorsun? Herhangi bir şey olabilir.
sebjwallace

2
@sebjwallace Ne seçerseniz seçin, bu karakter dizede bulunamaz demektir. Örneğin "balık & chips_are_great" verir [balık, cips, are_great] sanırım.
Joe

@Joe '&' yerine herhangi bir şey kullanabilirsiniz - bu sadece bir örnektir. İsterseniz _'in ilk tekrarını ¬ ile değiştirebilirsiniz. Yani "fish & chips_are_great", _'in ilk oluşumunu fish ile "fish & chips¬are_great" vermek için değiştirir, ardından ["fish & chips", "are_great"] elde etmek için ¬ ile bölünür
sebjwallace

8

Normal ifadeyi aşağıdaki gibi kullanabilirsiniz:

var arr = element.split(/_(.*)/)
Bölmenin sınırını belirten ikinci parametreyi kullanabilirsiniz. yani: var alan = element.split ('_', 1) [1];

6
Bu, yalnızca bölünmüş öğelerin kaç tanesinin döndürüldüğünü belirtir, kaç kez ayırdığını değil. 'good_luck_buddy'.split('_', 1);sadece döner['good']
Alex Vidal

Teşekkür bu konuda bir varsayım yaptı. Yayını, normal bir ifade kullanacak şekilde güncellendi.
Chandu

(:?.*)Yakalamayan bir grup olması gerekiyor muydu ? Öyleyse, olmalı (?:.*), ancak düzeltirseniz, artık işe yaramayacağını göreceksiniz. (:?.*)isteğe bağlı ve :ardından herhangi bir karakterin sıfır veya daha fazlasıyla eşleşir . Bu çözüm, @ MarkF'lerin yaptığı aynı nedenden dolayı sonuçlanır: _bir yakalama grubunda eşleştiği için ilk listeden sonraki her şey jeton listesine eklenir. (Ayrıca, gdeğiştiricinin bölünmüş bir normal ifadede kullanıldığında hiçbir etkisi yoktur.)
Alan Moore

Teşekkürler, farkında değildim. Regex güncellendi ve birkaç senaryo üzerinde çalıştı ...
Chandu

1
Yani ie8 çalışmıyor ve ben indexOf ve alt dize geri
Igor Alekseev

6

Bu çözüm benim için çalıştı

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"

VEYA

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
Ancak, ayırıcıda 1'den fazla karakter varsa bu çalışmaz.
haykam

5

Bugünlerde String.prototype.splitbölünme sayısını sınırlamanıza izin veriyor.

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

...

limit Opsiyonel

Bölme sayısını sınırlayan negatif olmayan bir tam sayı. Sağlanırsa, dizeyi belirtilen ayırıcının her tekrarında böler, ancak diziye sınır girişleri yerleştirildiğinde durur. Artık metinler diziye hiç dahil edilmez.

Dizinin sonuna, sınıra ulaşılmadan ulaşılırsa, dizi sınırdan daha az girdi içerebilir. Limit 0 ise, bölme yapılmaz.

uyarı

Beklediğiniz gibi çalışmayabilir. Sadece sınırlayıcıların geri kalanını görmezden geleceğini umuyordum, ancak bunun yerine, sınıra ulaştığında, geri kalan sonuçlardan ayrıldıktan sonra parçayı atlayarak kalan dizeyi tekrar böler.

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

Ben umuyordum:

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

Burada aynı. PHP "ilk" ve "geri kalanı" ayrılıyor gibi görünüyor.
BananaAcid

4

Javascript'in String.splitmaalesef gerçek bölünme sayısını sınırlama yolu yoktur. Gerçek bölünmüş öğelerin kaç tanesinin döndürüleceğini belirten ikinci bir bağımsız değişkeni vardır, bu da sizin durumunuzda yararlı değildir. Çözüm, dizeyi bölmek, ilk öğeyi kaydırmak, sonra kalan öğelere yeniden katılmak olacaktır:

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

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

Split işlevinin işe yaramadığını görüyorum, ancak bir regex kullanmak bunu başarıyor gibi görünüyor. Bölme işlevinin kendisine özgün olarak başvurduğunuzu belirtmelidir.
Dan Hanly

1
İlginç, Bu çözüm sorunu daha okunabilir / yönetilebilir bir çözüme kadar damıtmaktadır. Tam adı ilk ve son olarak dönüştürme durumumda (evet, gereksinimlerimiz bu mantığı zorladı) bu çözüm en iyi sonucu verdi ve diğerlerinden daha okunabilirdi. Teşekkürler
Sukima

Bu artık doğru değil :)
Kraken

3

İpin iki parçasına ihtiyacım var, bu yüzden regex lookbindind bu konuda bana yardım et.

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


3

Yıkım ataması yardımıyla daha okunabilir olabilir:

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

2

En hızlı çözüm?

Ben bazı kriterler koştu ve bu çözüm çok kazandı: 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);
};

Diğer çözümlerle performans karşılaştırması

Tek yakın yarışmacı kullanmak substryerine aynı kod satırıydı slice.

Dahil etmeye çalıştığım diğer çözümler splitveya RegExpperformans büyük bir hit aldı ve yaklaşık 2 derece daha yavaştı. Elbette joinsonuçlarını kullanmak , splitek bir performans cezası ekler.

Neden daha yavaşlar? Yeni bir nesne veya dizi oluşturulması gerektiğinde, JS'nin işletim sisteminden bir yığın bellek istemesi gerekir. Bu süreç çok yavaş.

Kıyaslamaları takip etmeniz durumunda bazı genel yönergeler aşağıda verilmiştir:

  • Nesneler {}veya diziler için [](oluşturanlar gibi) yeni dinamik bellek ayırma işlemlerinin splitperformansı çok maliyetli olacaktır.
  • RegExp aramalar dize aramalarından daha karmaşık ve dolayısıyla daha yavaştır.
  • Zaten bir diziniz varsa, dizileri yok etmek onları açıkça dizine eklemek kadar hızlıdır ve harika görünür.

İlk örneğin ötesinde kaldırma

İşte n'inci örneğe kadar dilimleyecek bir çözüm. Oldukça hızlı değil, ancak OP'nin sorusuna göre, gobble(element, '_', 1)bir RegExpveya splitçözümden > 2 kat daha hızlı ve daha fazlasını yapabilir:

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

Yukarıdaki tanımla, gobble('path/to/file.txt', '/')dosyanın adını verir ve gobble('prefix_category_item', '_', 1)bu yanıttaki ilk çözüm gibi öneki kaldırır.


  1. Testler macOSX 10.14'te Chrome 70.0.3538.110'da yapıldı.

Haydi ... 2019 ... Dışarıdaki insanlar hala bu tür şeyleri mikrobençliyor mu?
Victor Schröder

Katılıyorum. Mikro karşılaştırmalı değerlendirme biraz ilginç olsa da, optimizasyonlar için bir derleyiciye veya çevirmene güvenmelisiniz. Mb birisi bunu okuyan bir derleyici veya ejs / gömülü kullanıyor ve regex kullanamıyor. Ancak, bu benim özel durumum için bir normal ifade daha güzel görünüyor. ("En hızlı çözümü" kaldırırım)
TamusJRoyce

1

Mark F'nin çözümü harika, ancak eski tarayıcılar tarafından desteklenmiyor. Kennebec'nin çözümü harika ve eski tarayıcılar tarafından destekleniyor, ancak normal ifadeyi desteklemiyor.

Bu nedenle, dizenizi yalnızca bir kez bölen, eski tarayıcılar tarafından desteklenen ve normal ifadeyi destekleyen bir çözüm arıyorsanız, işte benim çözümüm:

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

Normal İfadeye alışkın olmayan yeni başlayanlar için bu geçici çözüm işe yaradı:

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

slice () yöntemi, bir dizenin bir bölümünü çıkarır ve yeni bir dize döndürür ve indexOf () yöntemi, bir dizede belirtilen bir değerin ilk bulunma konumunu döndürür.


Bu bir çözüm değil, ama bunu yapmanın uygun bir yoludur;)
Victor Schröder

1

replace()Bir regex ile string yöntemini kullanın :

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

Bu normal ifade birinciden önce 0 veya daha fazla karakterle _ve _kendisiyle eşleşir . Eşleşme daha sonra boş bir dizeyle değiştirilir.


Buradaki document.body.innerHTMLkısım tamamen işe yaramaz.
Victor Schröder

@ VictorSchröder Snippet'in çıktısını nasıl görmeyi bekliyorsunuz document.body.innerHTML?
James T

2
document.bodymevcut DOM'a bağlıdır ve saf bir JavaScript ortamında çalışmaz. console.logbu amaç için yeterlidir ya da sonucu muayene için bir değişken olarak bırakın.
Victor Schröder

@ VictorSchröder Çok fazla karışıklığa neden olacağını sanmıyorum, ama yine de düzenledim.
James T

0

Bu benim için Chrome + FF'de çalıştı:

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

Ayrıca anahtara ihtiyacınız varsa şunu deneyin:

"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

İşte hile yapan bir RegExp.

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

İlk olarak maçı baştan başlamak için '^' ile zorlar. Sonra '_' olmayan herhangi bir sayıda karakterle, yani ilk '_' öncesi tüm karakterlerle eşleşir.

'?' tüm kalıp eşleşmesini sağlayan en az sayıda karakter '. *?' çünkü onu daha sonra son karakteri olarak karşılaştıran '_' izler.

Bu nedenle bu split (), 'splitter' ile eşleşen bir parçayı kullanır ve sonuçlardan kaldırır. Böylece ilk '_' dahil olmak üzere her şeyi kaldırır ve geri kalanını sonucun 2. öğesi olarak verir. Birinci eleman, eşleşen bölümden önceki bölümü temsil eden "" dir. "" Çünkü maç baştan başlıyor.

Daha önce Chandu tarafından verilen /_(.*)/ gibi iyi çalışan başka RegExps'ler de var.

/^.*?_/, grupların replace () ile oynadığı özel rol yakalama hakkında bilmek zorunda kalmadan ne yaptığını anlayabilme avantajına sahiptir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.