JavaScript'te başka bir alt dize içeren bir dizeyi kontrol etmenin en hızlı yolu?


163

JavaScript'te bir performans sorunuyla çalışıyorum. Bu yüzden sadece sormak istiyorum: bir dize başka bir alt dize içerip içermediğini kontrol etmek için en hızlı yolu nedir (sadece boolean değeri gerekir)? Fikrinizi ve örnek snippet kodunuzu önerebilir misiniz?


Sabit bir alt dize mi soruyorsunuz, yoksa düzenli bir ifadeye mi ihtiyacınız var ( regexetiketin kullanımıyla biraz kafam karıştı )?
Tim Pietzcker


Dizeyi boşluk çevresindeki bir diziye bölmeye ve dizi kesişimine ne dersiniz? stackoverflow.com/questions/1885557/…
giorgio79

Yanıtlar:


315

İki olasılığınız var:

  1. Düzenli ifade :

    (new RegExp('word')).test(str)
    // or
    /word/.test(str)
  2. indexOf:

    str.indexOf('word') !== -1

Normal ifadeler daha hızlı görünüyor (en azından Chrome 10'da).

Performans testi - kısa samanlık
Performans testi - uzun samanlık


2011 Güncellemesi:

Hangi yöntemin daha hızlı olduğu kesin olarak söylenemez. Tarayıcılar arasındaki farklar çok büyük. Chrome 10'da indexOfdaha hızlı görünmekle birlikte, Safari 5'te indexOfdiğer yöntemlerden açıkça daha yavaştır.

Kendini görmek ve denemek zorundasın. Bu sizin ihtiyaçlarınıza bağlıdır. Örneğin, büyük / küçük harf duyarsız bir arama, normal ifadelerle çok daha hızlıdır.


Güncelleme 2018:

İnsanları testleri kendileri yapmaktan kurtarmak için, en yaygın tarayıcılar için mevcut sonuçlar şunlardır, yüzdeler bir sonraki en hızlı sonuçta (tarayıcılar arasında değişen) performans artışını gösterir:

Chrome: indexOf (~% 98 daha hızlı) <-- wow
Firefox: önbelleğe alınmış RegExp (~% 18 daha hızlı)
IE11: önbelleğe alınmış RegExp (~% 10 daha hızlı)
Kenar: indexOf (~% 18 daha hızlı)
Safari: önbelleğe alınmış RegExp (~% 0,4 daha hızlı)

Not RegExp önbelleğe geçerli: var r = new RegExp('simple'); var c = r.test(str);aksine:/simple/.test(str)


3
Bu, yalnızca aranacak metin önceden biliniyorsa (yani bir değişkende saklanmazsa) biraz daha hızlı olabilir, çünkü normal ifade ayrıştırma süresi boyunca JavaScript motoru tarafından oluşturulur. Başka bir dize değişkeni içinde bir değişkene içinde bulunan bir dize aramak istiyorsanız bir RegExp nesnesi oluşturmak gerekiyor ve vb özel karakterler kaçmayı dize işlemek istiyorum, çünkü indexOf en hızlı
Stephen Chung

Eğer ilk aradığınız şeyde .toLowerCase kullanırsanız, indexOf büyük / küçük harf duyarsız arama için daha hızlı olabilir
Hayk Saakian

Microsoft'un Office Javascript API'sini kullanarak bir Office 2013 Uygulaması yazıyorum ve kullanmak indexOfçalışmıyor. Neden olduğundan emin değilim. Regex kullanmak olsa da. Bu bir uç durumdur, ancak diğerleri aynı sorunla karşılaşabilir.
Andy Mercer

Herhangi bir sebep substr () olası çözümlerden biri değil mi? Birçok durumda RegEx çözümünden çok daha hızlı olduğunu tahmin ediyorum. Ben nasıl indexOf () karşılaştırır bilmiyorum (böylece her zaman indexOf () daha kötü performans çünkü dışarıda yaptıysanız, o zaman bu iyi, belki de bu etki için bir not ekleyin.) EDIT: Bu JSperf bağlantı bazı ilginç gösterir Sonuçlar. Kısa sürüm: indexOf () tüm yöntemlerin en hızlısıdır, ancak bu dize uzunluğuna ve yinelenen kalıplara bağlı olarak değişebilir.
Byson

1
@Bison: substr'yi yalnızca nereye bakacağınızı biliyorsanız kullanabilirsiniz. Sadece genel çözümlere odaklandım.
Felix Kling

17

Bu senin için uygun mu?

string1.indexOf(string2) >= 0

Düzenleme: string2 yinelenen desenler içeriyorsa, bu bir RegExp'ten daha hızlı olmayabilir. Bazı tarayıcılarda indexOf, RegExp'ten çok daha yavaş olabilir. Yorumlara bakınız.

Düzenleme 2: Dizeler çok uzun olduğunda ve / veya yinelenen desenler içerdiğinde RegExp, indexOf'tan daha hızlı olabilir. Yorumlara bakın ve @ Felix'in cevabı.


ancak bu diğer yöntemlerle nasıl karşılaştırılır? Bu en hızlı mı yoksa bunu yapmanın birçok yönteminden sadece biri mi?
Chii

Bu, JavaScript'in kendisi tarafından uygulandığı için hızlı olmalıdır (yani yerel kod çalıştırır). JavaScript koduna dayalı diğer tüm yöntemler daha yavaş olacaktır. Dizeyi tam olarak biliyorsanız, normal ifade biraz daha hızlı olabilir (JavaScript motorunun .indexOf'u bulmak için prototip zincirinde yürümesi gerekmez).
Stephen Chung

Büyük / küçük harfe duyarlı olmayan aramaya ihtiyacınız varsa, kesinlikle bir RegExp nesnesi oluşturmanız ve çağırmanız gerekir test.
Stephen Chung

3
Safari'de bir test yaptım. indexOfdiğer yöntemlerden daha yavaş bir büyüklüktür. Yani hangi yöntemin daha hızlı olduğu söylenemez. Tarayıcıdan tarayıcıya değişir.
Felix Kling

@ Felix, bu iyi bir gözlem (aslında kendiniz deneyene kadar hiçbir şeye güvenmeyin)! Çok sayıda tekrarlanan desene sahip dizelerde söylenen bir şeyi hatırlayarak belirsizleşirim, regex'ler basit bir döngü karşılaştırma uygulamasından daha hızlı performans göstermelidir çünkü regex'ler devlet makinelerine derlenir ve basit döngülerden çok daha hızlı geri izlenebilir - ki her zaman geri dönmelidir- sonraki karaktere git. Deneyi yapmak ve bunu ortaya çıkarmak için +1!
Stephen Chung

17

En hızlı

  1. (ES6) şunları içerir
    var string = "merhaba",
    substring = "lo";
    string.includes (substring);
  1. ES5 ve daha eski indexOf
    var string = "merhaba",
    substring = "lo";
    string.indexOf (alt dize)! == -1;

http://jsben.ch/9cwLJ

resim açıklamasını buraya girin


8

ES6'da includes()yöntem, bir dizenin başka bir dizede bulunup bulunmadığını belirlemek için kullanılır , döndürülür trueveya falseuygun şekilde.

var str = 'To be, or not to be, that is the question.';

console.log(str.includes('To be'));       // true
console.log(str.includes('question'));    // true
console.log(str.includes('nonexistent')); // false

İşte jsperf arasında

var ret = str.includes('one');

Ve

var ret = (str.indexOf('one') !== -1);

Jsperf'de gösterilen sonuç olarak, her ikisi de iyi performans gösteriyor gibi görünüyor.


İçeride "regex" ifadesini "argüman" olarak kullanabilir miyim? Gibi str.includes("x|y"):; aynı çağrıda "x" veya "y" kelimelerini arayın.
ptkato

@ Patrick, dahil doc başına, içinde kullanamazsınız regex. Sorunuz için bir çalışma,str.includes("x") || str.includes('y')
zangw

Chrome 59 JavaScript geliştirmelerinin bir sonucu olarak indexOf, önemli ölçüde daha hızlıdır includes(% 1600'den daha hızlı). 44 milyon iterasyon / sn ve 777+ milyon i / sn arasındaki farkın gerçek dünya performansını nasıl etkilediği açık değildir , ancak mobil cihaz indexOfideal seçim olması gereken kadar fayda sağlayacaktır .
Chad Levy

7

Ben döngü için basit bir kullanarak, dize tüm öğeleri üzerinde yineleme ve kullanarak karşılaştırma veya charAtdaha hızlı gerçekleştirdiğini buldum . Kod ve kanıt JSPerf adresinde mevcuttur .indexOfRegex

ETA: indexOfve charAther ikisi de jsperf.com'da listelenen Tarayıcı Kapsamı verilerine göre Chrome Mobile'da benzer şekilde korkunç performans gösteriyor


El yapımı bir fonksiyonun yerleşik olandan daha iyi olduğu garip, ancak sanırım iğne sadece bir karakter. Hala ...
Moss

Apple iPad'de (iOS 7.1.1) Chrome Mobile 36.0.1985.57'de test edildi. IndexOf daha hızlıdır. Üzgünüz
rpax

@rpax CharAt, hem IndexOf hem de CharAt'ın masaüstüne kıyasla eşit derecede düşük performans gösterdiği Chrome Mobile hariç tüm platformlarda (jsperf geçmişine bağlı olarak) hala önemli ölçüde daha hızlıdır .
wpg4665

1
Bunun NodeJS'de nasıl performans gösterdiğini görmek istiyorum ve bu sadece iyi bir örnek değil, çünkü sadece bir karakteri bir alt dize arıyorsunuz.
qodeninja

Bu geçerli bir cevap değil. Bir alt dize aramıyorsunuz, sadece tek bir karakterin ortaya çıkması
Henrik Myntti

3

Basit bir dize bulmak için, indexOf () yöntemini kullanmak ve regex kullanmak hemen hemen aynıdır: http://jsperf.com/substring - bu yüzden hangisinin daha kolay yazılacağını seçin.



1

.match()Dizge yöntemini kullanmanın kolay yolu .

var re = /(AND|OR|MAYBE)/;
var str = "IT'S MAYBE BETTER WAY TO USE .MATCH() METHOD TO STRING";
console.log('Do we found something?', Boolean(str.match(re)));

İyi günler dilerim efendim!


4
matchBir testyöntem olduğunda bir neden yok … En iyi cevaba göz atın.
Bergi
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.