Bir dizenin tamamen aynı alt dizeden oluşup oluşmadığını nasıl kontrol ederim?


128

Bir dizge alan bir işlev oluşturmalıyım ve geri dönmeli trueveya falsegirdinin tekrarlanan bir karakter dizisinden oluşup oluşmadığına bağlı. Verilen dizenin uzunluğu her zaman değerinden daha büyüktür 1ve karakter dizisinin en az bir tekrarı olmalıdır.

"aa" // true(entirely contains two strings "a")
"aaa" //true(entirely contains three string "a")
"abcabcabc" //true(entirely containas three strings "abc")

"aba" //false(At least there should be two same substrings and nothing more)
"ababa" //false("ab" exists twice but "a" is extra so false)

Aşağıdaki işlevi oluşturdum:

function check(str){
  if(!(str.length && str.length - 1)) return false;
  let temp = '';
  for(let i = 0;i<=str.length/2;i++){
    temp += str[i]
    //console.log(str.replace(new RegExp(temp,"g"),''))
    if(!str.replace(new RegExp(temp,"g"),'')) return true;
  }
  return false;
}

console.log(check('aa')) //true
console.log(check('aaa')) //true
console.log(check('abcabcabc')) //true
console.log(check('aba')) //false
console.log(check('ababa')) //false

Bunu kontrol etmek gerçek sorunun bir parçasıdır. Böyle verimli olmayan bir çözümü karşılayamam. Her şeyden önce, dizenin yarısından geçiyor.

İkinci sorun, replace()her döngüde onu yavaşlatan kullanmasıdır. Performansla ilgili daha iyi bir çözüm var mı?


19
Bu bağlantı sizin için faydalı olabilir. Geekforgeeks'i her zaman algoritma problemleri için iyi bir kaynak olarak buluyorum - geeksforgeeks.org/…
Leron_says_get_back_Monica

9
Bunu ödünç alıp Programming Golf değişim sitesinde bir kodlama sınavı haline getirmemin bir sakıncası var mı?
ouflak

7
@ouflak bunu yapabilirsin.
Maheer Ali

12

24
@Shidersz Bunun için Sinir ağlarını kullanmak, sivrisinek vurmak için top kullanmak gibi bir his.
JAD

Yanıtlar:


186

Bunun gibi dizelerle ilgili şık ve küçük bir teorem var.

Bir dizge birden çok kez yinelenen aynı örüntüden oluşur, ancak ve ancak dizge kendisinin önemsiz olmayan bir dönüşüyse.

Burada döndürme, dizenin önünden birkaç karakterin silinmesi ve arkaya taşınması anlamına gelir. Örneğin, dize helloşu dizelerden herhangi birini oluşturmak için döndürülebilir:

hello (the trivial rotation)
elloh 
llohe 
lohel 
ohell 

Bunun neden işe yaradığını görmek için, önce bir dizenin bir w dizesinin tekrarlanan k kopyasından oluştuğunu varsayalım. Ardından, tekrarlanan desenin (w) ilk kopyasını dizenin önünden silmek ve arkaya yapıştırmak aynı dizeyi geri verecektir. Ters yönü kanıtlamak biraz daha zordur, ancak fikir şu ki, bir dizgiyi döndürür ve başladığınız şeyi geri alırsanız, dizeyi aynı desenin birden çok kopyasıyla döşemek için bu dönüşü tekrar tekrar uygulayabilirsiniz (bu model, dönüşü yapmak için sonuna gitmeniz gereken dize).

Şimdi soru, durumun bu olup olmadığını nasıl kontrol edeceğidir. Bunun için kullanabileceğimiz başka bir güzel teorem var:

X ve y aynı uzunlukta dizeler ise, o zaman x, ancak ve ancak x, yy'nin bir alt dizesi ise, y'nin bir dönüşüdür.

Örnek olarak, bunun aşağıdaki gibi lohelbir dönüş olduğunu görebiliriz hello:

hellohello
   ^^^^^

Bizim durumumuzda, her x dizesinin her zaman xx'in bir alt dizesi olacağını biliyoruz (x'in her kopyasında bir kez olmak üzere iki kez görünecektir). Yani temelde, x dizgimizin, xx'in bir alt dizesi olup olmadığını kontrol etmemiz gerekiyor, ilk veya yarı karakterle eşleşmesine izin vermeden. İşte bunun için tek satırlık:

function check(str) {
    return (str + str).indexOf(str, 1) !== str.length;
}

indexOfHızlı bir dizgi eşleştirme algoritması kullanılarak uygulandığını varsayarsak , bu O (n) zamanında çalışacaktır, burada n, girdi dizgesinin uzunluğudur.

Bu yardımcı olur umarım!


13
Çok hoş! Bunu jsPerf karşılaştırma sayfasına ekledim .
user42723

10
@ user42723 Harika! Görünüşe göre gerçekten çok hızlı.
templatetypedef

5
Bilginize: Şu ifadeyi tersine çevirene kadar bu cümleyi inanmakta zorlandım: "Bir dizge, ancak ve ancak birden çok kez tekrarlanan aynı kalıptan oluşuyorsa, kendisinin önemsiz olmayan bir rotasyonudur". Şekle gidin.
Axel Podehl

11
Bu teoremlere referanslarınız var mı?
HRK44

4
Bence ilk ifade, doi.org/10.1016/j.tcs.2008.04.020 adresindeki " Lemma 2.3 : x ve x'in dönüşü eşitse, x bir tekrardır " . Ayrıca bakınız: stackoverflow.com/a/2553533/1462295
BurnsBA

67

Bunu bir yakalama grubu ve geri referans ile yapabilirsiniz . Sadece ilk yakalanan değerin tekrarı olduğunu kontrol edin.

function check(str) {
  return /^(.+)\1+$/.test(str)
}

console.log(check('aa')) //true
console.log(check('aaa')) //true
console.log(check('abcabcabc')) //true
console.log(check('aba')) //false
console.log(check('ababa')) //false

Yukarıdaki Normal İfadede:

  1. ^ve konumu tahmin etmek $için başlangıç ​​ve bitiş bağlantılarını ifade eder.
  2. (.+)herhangi bir deseni yakalar ve değeri yakalar (hariç \n).
  3. \1ilk yakalanan değerin geri referansıdır ve yakalanan değerin \1+tekrarını kontrol eder.

Burada normal ifade açıklaması

RegExp hata ayıklaması için şunu kullanın: https://regex101.com/r/pqlAuP/1/debugger

Performans: https://jsperf.com/reegx-and-loop/13


2
Bize bu satırın ne yaptığını açıklayabilir misiniz return / ^(.+)\1+$
test(

34
Ayrıca bu çözümün karmaşıklığı nedir? Kesinlikle emin değilim ama OP'nin sahip olduğundan çok daha hızlı görünmüyor.
Leron_says_get_back_Monica

8
@PranavCBalan Algoritmalarda iyi değilim, bu yüzden yorumlar kısmına yazıyorum. Ancak bahsetmem gereken birkaç şey var - OP'nin zaten çalışan bir çözümü var, bu yüzden ona daha iyi performans sağlayacak bir çözüm istiyor ve çözümünüzün kendisinden daha iyi nasıl performans göstereceğini açıklamadınız. Daha kısa demek daha hızlı demek değildir. Ayrıca, verdiğiniz bağlantıdan: If you use normal (TCS:no backreference, concatenation,alternation,Kleene star) regexp and regexp is already compiled then it's O(n).ama yazdığınız gibi geri referans kullanıyorsunuz, bu yüzden hala O (n)?
Leron_says_get_back_Monica

5
Yeni satır karakterlerini diğer karakterlerle aynı şekilde eşleştirmeniz gerekiyorsa [\s\S]bunun yerine kullanabilirsiniz .. Nokta karakteri yeni satırlarla eşleşmiyor; alternatif tüm beyaz boşluk ve boşluk olmayan karakterleri arar, bu da eşleşmeye yeni satırların dahil edildiği anlamına gelir. (Bunun daha sezgisel olandan daha hızlı olduğuna dikkat edin (.|[\r\n]).) Ancak, dizge kesinlikle yeni satırlar içermiyorsa, basit .en hızlı olacaktır. Dotall bayrağı uygulandığında bunun çok daha basit olacağını unutmayın .
HappyDog

2
/^(.+?)\1+$/Biraz daha hızlı değil mi? (12 adım vs 20 adım)
çevrimiçi Thomas

29

Belki de en hızlı algoritmik yaklaşım, doğrusal zamanda bir Z işlevi oluşturmaktır:

Bu dizge için Z işlevi, i'inci öğenin s'nin ilk karakterleriyle çakışan i konumundan başlayan en büyük karakter sayısına eşit olduğu, n uzunluğunda bir dizidir.

Başka bir deyişle, z [i], s ile i'den başlayan s soneki arasındaki en uzun ortak ön ekin uzunluğudur.

Başvuru için C ++ uygulaması:

vector<int> z_function(string s) {
    int n = (int) s.length();
    vector<int> z(n);
    for (int i = 1, l = 0, r = 0; i < n; ++i) {
        if (i <= r)
            z[i] = min (r - i + 1, z[i - l]);
        while (i + z[i] < n && s[z[i]] == s[i + z[i]])
            ++z[i];
        if (i + z[i] - 1 > r)
            l = i, r = i + z[i] - 1;
    }
    return z;
}

JavaScript uygulaması
Eklenen optimizasyonlar - z dizisinin yarısını oluşturma ve erken çıkış

function z_function(s) {
  var n = s.length;
  var z = Array(n).fill(0);
  var i, l, r;
  //for our task we need only a half of z-array
  for (i = 1, l = 0, r = 0; i <= n/2; ++i) {
    if (i <= r)
      z[i] = Math.min(r - i + 1, z[i - l]);
    while (i + z[i] < n && s[z[i]] == s[i + z[i]])
      ++z[i];

      //we can check condition and return here
     if (z[i] + i === n && n % i === 0) return true;
    
    if (i + z[i] - 1 > r)
      l = i, r = i + z[i] - 1;
  }
  return false; 
  //return z.some((zi, i) => (i + zi) === n && n % i === 0);
}
console.log(z_function("abacabacabac"));
console.log(z_function("abcab"));

Sonra in'yi bölen dizinleri kontrol etmeniz gerekir . Böyle bulursanız io i+z[i]=nsonra dize suzunluğuna sıkıştırılmış olabilir ive siz dönebilirsiniz true.

Örneğin,

string s= 'abacabacabac'  with length n=12`

z dizisi

(0, 0, 1, 0, 8, 0, 1, 0, 4, 0, 1, 0)

ve bunu bulabiliriz

i=4
i+z[i] = 4 + 8 = 12 = n
and
n % i = 12 % 4 = 0`

bu nedenle s, üç kez tekrarlanan uzunluk 4'ün alt dizesi olarak gösterilebilir.


3
return z.some((zi, i) => (i + zi) === n && n % i === 0)
Pranav C Balan

2
Salman A ve Pranav C
Balan'a

1
Ek bir yineleme kaçınarak Alternatif yaklaşımconst check = (s) => { let n = s.length; let z = Array(n).fill(0); for (let i = 1, l = 0, r = 0; i < n; ++i) { if (i <= r) z[i] = Math.min(r - i + 1, z[i - l]); while (i + z[i] < n && s[z[i]] == s[i + z[i]]) ++z[i]; // check condition here and return if (z[i] + i === n && n % i === 0) return true; if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1; } // or return false return false; }
Pranav C Balan

2
Z işlevini kullanmak iyi bir fikirdir, ancak 'bilgi-ağırdır', asla kullanılmayan pek çok bilgi içerir.
Axel Podehl

@Axel Podehl Yine de, dizgeyi O (n) sürede ele alır (her karakter en fazla iki kez kullanılır). Her durumda her karakteri kontrol etmeliyiz, bu nedenle teorik olarak daha hızlı bir algoritma yok (optimize edilmiş yerleşik yöntemler daha iyi performans gösterebilirken). Ayrıca son düzenlemede hesaplamayı tel uzunluğunun 1 / 2'si ile sınırladım.
MBo

23

Gnasher729'un cevabını okudum ve uyguladım. Buradaki fikir, eğer herhangi bir tekrar varsa, o zaman (aynı zamanda) asal sayıda tekrar olması gerektiğidir.

function* primeFactors (n) {
    for (var k = 2; k*k <= n; k++) {
        if (n % k == 0) {
            yield k
            do {n /= k} while (n % k == 0)
        }
    }
    if (n > 1) yield n
}

function check (str) {
    var n = str.length
    primeloop:
    for (var p of primeFactors(n)) {
        var l = n/p
        var s = str.substring(0, l)
        for (var j=1; j<p; j++) {
            if (s != str.substring(l*j, l*(j+1))) continue primeloop
        }
        return true
    }
    return false
}

Biraz farklı bir algoritma şudur:

function check (str) {
    var n = str.length
    for (var p of primeFactors(n)) {
        var l = n/p
        if (str.substring(0, n-l) == str.substring(l)) return true
    }
    return false
}

Bu sayfada kullanılan algoritmaları içeren jsPerf sayfasını güncelledim .


Gereksiz kontrolleri atladığı için bu gerçekten hızlı görünüyor.
Pranav C Balan

1
Çok güzel, sadece alt dize çağrılarını yapmadan önce ilk harfin belirtilen konumda yeniden oluştuğunu kontrol edeceğimi düşünüyorum.
Ben Voigt

function*Benim gibi ilk kez tökezleyen insanlar için bu, normal bir işlev değil, bir jeneratör bildirmek içindir. Bkz MDN
Julien Rousé

17

S dizesinin N uzunluğuna sahip olduğunu ve s alt dizesinin kopyalarından oluştuğunu varsayalım, bu durumda s uzunluğu N'yi böler. Örneğin, S'nin uzunluğu 15 ise, alt dizenin uzunluğu 1, 3 veya 5 olur.

S, s'nin (p * q) kopyalarından yapılsın. Daha sonra S ayrıca (s, q kez tekrarlanan) p kopyasından oluşur. Bu nedenle iki durumumuz var: Eğer N asal veya 1 ise, S yalnızca 1 uzunluğundaki alt dizenin kopyalarından yapılabilir. N kompozit ise, o zaman p bölünen asallar için yalnızca N / p uzunluğundaki alt dizeleri kontrol etmemiz gerekir. S.'nin uzunluğu

Öyleyse N = S'nin uzunluğunu belirleyin, sonra tüm asal çarpanlarını O (sqrt (N)) zamanında bulun. Yalnızca bir N faktörü varsa, S'nin aynı dizenin N kez tekrarlandığını kontrol edin, aksi takdirde her bir asal faktör p için, S'nin ilk N / p karakterlerinin p tekrarlarından oluşup oluşmadığını kontrol edin.


Diğer çözümleri kontrol etmedim, ancak bu çok hızlı görünüyor. Bu özel bir durum olmadığından, basitlik için "Yalnızca bir N faktörü varsa, kontrol et ..., aksi takdirde" bölümünü atlayabilirsiniz. Diğer uygulamaların yanında jsPerf'de çalıştırılabilen bir Javascript uygulaması görmek güzel olurdu.
user42723

1
Şimdi bu uyguladık cevabım
user42723

10

Yinelemeli bir işlev de çok hızlı olabilir. İlk gözlem, maksimum tekrarlanan desen uzunluğunun toplam dizginin yarısı kadar olmasıdır. Ve tüm olası tekrarlanan desen uzunluklarını test edebiliriz: 1, 2, 3, ..., str.length / 2

Özyinelemeli işlevi, bu kalıbın str içinde tekrarlanıp yinelenmediğini test eder.

Eğer str, desenden daha uzunsa, özyineleme, ilk kısmın (p ile aynı uzunlukta) str'nin geri kalanının yanı sıra bir tekrar olmasını gerektirir. Böylece str, etkin bir şekilde p. Uzunluklu parçalara ayrılır.

Test edilen desen ve dizge eşit boyuttaysa, yineleme burada başarıyla sona erer.

Uzunluk farklıysa ("aba" ve örüntü "ab" için geçerliyse) veya parçalar farklıysa, o zaman yanlış döndürülür ve özyinelemeyi yayar.

function check(str)
{
  if( str.length==1 ) return true; // trivial case
  for( var i=1;i<=str.length/2;i++ ) { // biggest possible repeated pattern has length/2 characters

    if( str.length%i!=0 ) continue; // pattern of size i doesn't fit
    
    var p = str.substring(0, i);
    if( isRepeating(p,str) ) return true;
  }
  return false;
}


function isRepeating(p, str)
{
  if( str.length>p.length ) { // maybe more than 2 occurences

    var left = str.substring(0,p.length);
    var right = str.substring(p.length, str.length);
    return left===p && isRepeating(p,right);
  }
  return str===p; 
}

console.log(check('aa')) //true
console.log(check('aaa')) //true 
console.log(check('abcabcabc')) //true
console.log(check('aba')) //false
console.log(check('ababa')) //false

Performans: https://jsperf.com/reegx-and-loop/13


1
if( str===p.repeat(str.length/i) ) return true;Özyinelemeli bir işlev kullanmak yerine kontrol etmek daha hızlı olur mu?
Chronocidal

1
Console.log'ları jsperf testlerine koymayın, globals bölümündeki işlevleri hazırlayın, ayrıca globals bölümündeki test dizelerini hazırlayın (üzgünüm, jsperf değiştirilemez)
Salman A

@Salman - iyi nokta. Jsperf'i selefimden (Pranav C) değiştirdim, ilk kez jsperf, harika bir araç kullandım.
Axel Podehl

@SalmanA: güncellendi: jsperf.com/regex-and-loop/1 ... bilgi için teşekkürler ... aşina olmasam bile (Jsperf) ... bilgi için teşekkürler
Pranav C Balan

Merhaba Salman, jsperf.com/reegx-and-loop/10 için çok teşekkürler - evet, bu yeni performans testi çok daha mantıklı. Fonksiyonların kurulumu hazırlık koduna girmelidir.
Axel Podehl

7

Bunu Python'da yazdım. Platform olmadığını biliyorum, ancak 30 dakika sürdü. PS => PYTHON

def checkString(string):
    gap = 1 
    index= 0
    while index < len(string)/2:
        value  = [string[i:i+gap] for i in range(0,len(string),gap) ]

        x = [string[:gap]==eachVal for eachVal in value]

        if all(x):
            print("THEY ARE  EQUAL")
            break 

        gap = gap+1
        index= index+1 

checkString("aaeaaeaaeaae")

6

Benim yaklaşımım gnasher729'a benziyor, çünkü alt dizenin potansiyel uzunluğunu ana odak olarak kullanıyor, ancak daha az matematik ve işlem yoğun:

L: Orijinal dizinin uzunluğu

S: Geçerli alt dizelerin potansiyel uzunlukları

L / 2'den 1'e S döngüsü (tamsayı kısmı). L / S bir tamsayı ise, orijinal dizenizi L / S kez tekrarlanan orijinal dizenin ilk S karakterlerine karşı kontrol edin.

1'den itibaren değil L / 2'den geriye doğru döngü oluşturmanın nedeni, mümkün olan en büyük alt dizeyi elde etmektir. 1'den L / 2'ye kadar olası en küçük alt dize döngüsünü istiyorsanız. Örnek: "abababab", olası alt dizeler olarak hem "ab" hem de "abab" içerir. Yalnızca doğru / yanlış sonucu önemsiyorsanız, ikisinden hangisinin daha hızlı olacağı, bunun uygulanacağı dizelerin / alt dizelerin türüne bağlıdır.


5

Aşağıdaki Mathematica kodu , listenin en az bir kez tekrarlanıp tekrarlanmadığını neredeyse algılar. Dize en az bir kez tekrarlanırsa, doğru döndürür, ancak dize, tekrarlanan dizelerin doğrusal bir birleşimiyse de doğru sonucunu döndürebilir.

IsRepeatedQ[list_] := Module[{n = Length@list},
   Round@N@Sum[list[[i]] Exp[2 Pi I i/n], {i, n}] == 0
];

Bu kod, yinelenen bir dizede sıfır olması gereken "tam uzunlukta" katkıyı arar, ancak dizenin accbbdaynı zamanda yinelenen iki dizenin toplamı olduğu abababve 012012.

Buradaki fikir, Hızlı Fourier Dönüşümü kullanmak ve frekans spektrumlarını aramaktır. Diğer frekanslara bakılarak da bu garip senaryoyu tespit etmek gerekir.


4

Buradaki temel fikir, herhangi bir potansiyel alt dizeyi, 1 uzunluğundan başlayıp orijinal dizginin uzunluğunun yarısında durarak incelemektir. Yalnızca orijinal dizgi uzunluğunu eşit olarak bölen alt dize uzunluklarına bakarız (yani str.length% substring.length == 0).

Bu uygulama, ikinci karaktere geçmeden önce olası her alt dize yinelemesinin ilk karakterine bakar; bu, alt dizelerin uzun olması bekleniyorsa zaman kazandırabilir. Tüm alt dizeyi inceledikten sonra hiçbir uyumsuzluk bulunmazsa, true değerini döndürürüz.

Kontrol edilecek potansiyel alt dizeler kalmadığında yanlış döndürürüz.

function check(str) {
  const len = str.length;
  for (let subl = 1; subl <= len/2; ++subl) {
    if ((len % subl != 0) || str[0] != str[subl])
      continue;
    
    let i = 1;
    for (; i < subl; ++i)
    {
      let j = 0;
      for (; j < len; j += subl)
        if (str[i] != str[j + i])
          break;
      if (j != len)
        break;
    }
    
    if (i == subl)
      return true;
  }
  return false;
}

console.log(check('aa')) //true
console.log(check('aaa')) //true
console.log(check('abcabcabc')) //true
console.log(check('aba')) //false
console.log(check('ababa')) //false


-1

JavaScript'e aşina değilim, bu yüzden bunun ne kadar hızlı olacağını bilmiyorum, ancak burada yalnızca yerleşikleri kullanan doğrusal bir zaman çözümü (makul yerleşik uygulama varsayılarak) var. Algoritmayı sözde kodda tanımlayacağım.

function check(str) {
    t = str + str;
    find all overlapping occurrences of str in t;
    for each occurrence at position i
        if (i > 0 && i < str.length && str.length % i == 0)
            return true;  // str is a repetition of its first i characters
    return false;
}

Fikir, MBo'nun cevabına benzer. iUzunluğu bölen her biri için str, ilk ikarakterlerin tekrarı, ancak ve ancak ikarakterler için kaydırıldıktan sonra aynı kalırsa .

Aklıma böyle bir yerleşikin kullanılamaz veya verimsiz olabileceği geliyor. Bu durumda, KMP algoritmasını manuel olarak uygulamak her zaman mümkündür , bu da MBo'nun cevabındaki algoritma ile yaklaşık aynı miktarda kod alır.


OP tekrarı olmadığını bilmek istiyor vardır . Fonksiyonunuzun ikinci satırı (gövdesi) tekrarların sayısını sayar - bu açıklanması gereken bittir. Örneğin "abcabcabc", "abc" nin 3 tekrarı içeriyor, ancak ikinci satırınız herhangi bir tekrar olup olmadığını nasıl anladı ?
Lawrence

@Lawrence Sorunuzu anlamıyorum. Bu algoritma dize ancak ve ancak uzunluğunun bazı bölen için eğer onun alt dize tekrarı olduğu fikrine dayanmaktadır i, s[0:n-i] == s[i:n],, veya eşdeğer s == s[i:n] + s[0:i]. Neden ikinci satırın herhangi bir tekrar olup olmadığını hesaplaması gerekiyor?
infmagic2047

Algoritmanızı anlayıp anlamadığıma bir bakayım. Önce strforma eklersiniz t, sonra içini tbulmaya çalışırsınız . Tamam, bu işe yarayabilir (Olumsuz oyumu geri çektim). Gerçi strlen (str) 'de doğrusal değildir. Diyelim uzunluğu L'dir. Sonra her pozisyonda p = 0,1,2, ..., str [0..L-1] == t [p..p + L-1] 'in O (L ) zaman. P'nin değerlerinin üzerinden geçerken O (L) kontrolleri yapmanız gerekir, yani O (L ^ 2) olur. strtstr
Lawrence

-10

Basit fikirlerden biri, dizeyi "" alt dizesiyle değiştirmektir ve eğer herhangi bir metin varsa o zaman yanlıştır, aksi takdirde doğrudur.

'ababababa'.replace(/ab/gi,'')
"a" // return false
'abababab'.replace(/ab/gi,'')
 ""// return true


evet, abc veya tek boynuzlu at için kullanıcı / abc / veya / unicorn / ile kontrol etmez, eğer içeriğinizi kaçırıyorsam özür dilerim
Vinod kumar G

3
Soru daha net olabilir, ancak sorduğu şey, dizenin tamamen başka herhangi bir dizinin 2 veya daha fazla tekrarından oluşup oluşmadığına karar vermenin bir yoludur. Belirli bir alt dizeyi aramıyor.
HappyDog

2
Soruya şimdi daha açık hale getirmesi gereken bazı açıklamalar ekledim.
HappyDog

@Vinod, zaten regex'i kullanacaksanız, eşleşmenizi sabitlemeli ve testi kullanmalısınız. Sadece bazı koşulları doğrulamak için dizeyi değiştirmeye gerek yok.
Marie
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.