2009-09-27 7 views
5

Zostałem poproszony o to pytanie w wywiadzie dla stażu, a pierwszym rozwiązaniem, które zasugerowałem, było użycie wyrażenia regularnego (zwykle jestem trochę zaskoczony w wywiadach). Coś podobnego do tego:W "aa67bc54c9", czy istnieje sposób drukowania "aa" 67 razy, "bc" 54 razy itd., Używając wyrażeń regularnych?

(?P<str>[a-zA-Z]+)(?P<n>[0-9]+) 

Myślałem, że pasuje do napisów i zapisuje je w zmiennej "str" ​​oraz liczby w zmiennej "n". Jak nie byłem tego pewien.

Tak więc pasuje do ciągów typu "a1b2c3", ale problem polega na tym, że pasuje również do ciągów typu "a1b". Czy ktoś mógłby zaproponować rozwiązanie tego problemu?

Czy istnieje również inne wyrażenie regularne, które może rozwiązać ten problem?

+26

Nie jestem odpowiedzią, ale nie mogłem się oprzeć, cytując to: "Niektórzy ludzie, w konfrontacji z problemem, myślą:" Wiem, użyję wyrażeń regularnych ". Teraz mają dwa problemy. " - Jamie Zawinski –

+0

Ten cytat z Jamie Z jest jednym z moich ulubionych. – APC

+0

Pascal MARTIN - Chciałbyś mnie oświecić, dlaczego mają dwa problemy? (Naprawdę chcę wiedzieć). ---- O tym pytaniu, myślę, że RegEx wygląda mi dobrze i nie wygląda na to, żeby pasowało do "a1b". Jesteś pewien, Siddhant? – NawaMan

Odpowiedz

20

jak about:

while ($line =~ s/^([a-z]+)(\d+)//i) 
{ 
    print $1 x $2; 
} 
+1

używanie regex jest zbyt łatwe w twoim języku, w java musiałbym napisać o wiele więcej. – IAdapter

+3

Idź gadżet gadżet Perl! – tster

+4

@ 01: Może używasz niewłaściwego języka? A może nie powinieneś używać wyrażeń regularnych w swoim języku? A może potrzebujesz lepszej biblioteki regex w swoim języku. –

7

Odpowiadając na zapytanie bezpośrednio:

  • No, wyrażenia regularne tekst mecz i niczego nie drukuje, więc nie ma sposobu, aby to zrobić wyłącznie za pomocą wyrażeń regularnych .

Podane wyrażenie regularne będzie pasowało do jednej pary znaków/liczb; możesz następnie drukować to wielokrotnie, używając odpowiedniego mechanizmu. Rozwiązanie Perla z @tster jest tak kompaktowe, jak to tylko możliwe. (Nie używa nazw, które zastosowałeś w swoim regex, jestem prawie pewien, że to nie ma znaczenia.)

Pozostałe szczegóły zależą od języka implementacji.

33

Czy wiesz, dlaczego "wyrazy regularne" są nazywane "zwykłymi"? :-)

To byłoby zbyt długie, aby wytłumaczyć, po prostu zarysuję drogę. Aby dopasować wzorzec (to znaczy zdecydować, czy dany ciąg jest "prawidłowy" lub "nieprawidłowy"), teoretyczny informatyk użyłby finite state automaton. To abstrakcyjna maszyna, która ma skończoną liczbę stanów; przy każdym tiku odczytuje znak z wejścia i przeskakuje do innego stanu. Skala miejsca przeskakiwania z określonego stanu, gdy czytany jest dany znak, jest stała. Niektóre stany są oznaczone jako "OK", niektóre - jako "NIEPOWODZENIE", dzięki czemu sprawdzając stan maszyny, możesz sprawdzić, czy Twój tekst jest "ważny" (tj. Ważny e-mail).

Na przykład, maszyna ta przyjmuje tylko „nice” jako „ważny” słowo (PIC z Wikipedii):

a picture from Wikipedia article referenced above

Zestaw „ważny” słów taka maszyna teoretycznie można odróżnić od nieprawidłowy to "regular language". Nie każdy zbiór jest zwykłym językiem: na przykład, automaty skończone nie są w stanie sprawdzić, czy nawiasy w łańcuchu są zrównoważone.

Ale konstruowanie maszyn stanu było złożonym zadaniem, w porównaniu ze złożonością definiowania, co jest "poprawne". Tak więc matematycy (głównie S. Kleene) zauważyli, że każde regular language można opisać za pomocą "regular expression". Mieli * s i | s i były prototypami tego, co znamy teraz jako regexps.


Co to ma wspólnego z problemem?Problem w temacie jest zasadniczo nieregularny. Nie można go wyrazić za pomocą niczego, co działa jak automat skończony.

Najważniejsze jest to, że powinien zawierać komórkę pamięci zdolną do przechowywania dowolnej liczby (liczba powtórzeń w twoim przypadku). Automaty skończone i klasyczne wyrażenia regularne nie mogą tego zrobić.

Jednak współczesne wyrazy regularne są bardziej wyraziste i are said to be able to check balanced parentheses! Ale może to być dobrym przykładem, że nie powinieneś używać wyrażeń regularnych do zadań, które im nie odpowiadają. Nie mówiąc o tym, że zawiera fragmenty kodu; to sprawia, że ​​wyrażenie nie jest "regularne".

Odpowiedzi na pierwsze pytanie, nie można rozwiązać problemu za pomocą niczego "zwykłego" tylko. Jednakże, wyrażenia regularne mogą być pomóc w rozwiązaniu tego problemu, jak w tster's answer


Być może należy szukać bliżej tster's answer (zrobić „+1” Nie, proszę!) I pokazać, dlaczego nie jest to „normalne wyrażenie "rozwiązanie. Można pomyśleć, że tak jest, zawiera on tylko instrukcję print (nieistotną), a koncepcja loop-and-loop jest kompatybilna z skończoną automatyczną ekspresją automatu stanu. Ale jest jeszcze jedna nieuchwytny rzecz:

while ($line =~ s/^([a-z]+)(\d+)//i) 
{ 
    print $1 
      x # <--- this one 
       $2; 
} 

Zadaniem czyta ciąg i numer i drukowanie wielokrotnie ten ciąg podano liczbę razy, gdzie liczba jest dowolną liczbą całkowitą, to cofnąć w stanie skończonej maszyna bez dodatkowej pamięci. Używasz komórki pamięci, aby zachować tę liczbę i ją zmniejszyć, i sprawdzić, czy jest ona większa od zera. Ale ta liczba może być arbitralnie duża i jest sprzeczna z skończoną skończoną pamięcią dostępną dla maszyny stanowej skończonej.

Jednak nie ma nic złego w klasycznym wzorze /([abc]*){5}/, który pasuje do czegoś "regularnego" powtórzonego naprawiono liczbę razy. Zasadniczo mamy stany, które odpowiadają "dopasowanemu wzorowi raz", "dopasowanemu wzorowi dwa razy" ... "dopasowanemu wzorowi 5 razy". Jest ich skończona liczba i to jest istotna różnica.

+0

Piękne obrazy; ciekawy komentarz. Po prostu nie jestem pewien, "problem w temacie jest zasadniczo nieregularny". Jest bardzo regularny - ale nie można tego zrobić tylko za pomocą wyrażeń regularnych. –

+0

Wyrażenie regularne w mojej odpowiedzi używa tylko zwykłej gramatyki, bez rozszerzeń. Po prostu pętle i wydruki w Perlu. – tster

+1

@ Jonathan Leffler: dzięki za wskazanie, użyję innego słowa. @tster: Będę edytować moją odpowiedź, analizując twoje rozwiązanie i dlaczego nie "używa regularnej gramatyki". –

4

Nie, to jest twoje podstawowe "podchwytliwe pytanie" - bez względu na to, jak na nie odpowiesz, ta odpowiedź jest błędna, chyba że masz dokładnie odpowiedź, że ankieter został przeszkolony do papugi. Zobacz przeróbkę problemu podanego przez Pavel Shved - zauważ, że wszystkie wywołania mają "nie" jako typowy warunek, narzędzie po prostu ślizga się: Nawet gdy zmienia stan, nie ma licznika w tym stanie.

Mam dość zaawansowana książka Kennetha C Loudena, który jest profesorem w tej dziedzinie, w której stwierdza się, że kwestia jest skodyfikowana jako "Regex nie może liczyć". Oczywistą odpowiedzią na to pytanie wydaje mi się być w tej chwili, że używam poprzedniej cechy Regexa ...

Prawdopodobnie zależy od tego, z jakiej wersji marki regex korzysta ankieter, co prawdopodobnie zależy od dynamiki lotu Piłki golfowe.

+0

Nie zgadzam się z Twoją oceną "podchwytliwego pytania". Kiedy przeczytałem pytanie, ankieter tylko określił dane wejściowe i pożądane wyniki. Używanie wyrażenia regularnego do przejścia z punktu A do punktu B było pomysłem PO, a nie warunkiem narzuconym przez ankietera. –

+0

@Dave: Zauważ, i popraw. Brakowało mi, jak się tam dostać, był pomysł PO: OP stwierdza: "Zadano mi to pytanie w wywiadzie dla stażu", z którego wywnioskowałem, że OP zadano mi to pytanie w wywiadzie na staż - fakt, że ja podpaliłem Ankieter pochodzi ze środowisk przemysłowych, w których pracuję, gdzie 304 Stainless otula takich ankieterów sprzętem ochronnym, który jest bezzębny i nie może być używany w sposób ukierunkowany. Jeśli jesteś "Pro From Dover", to jest warte wysiłku, zbyt często jest to kandydat Master Crypto Thesis vs ktoś, kto faktycznie prowadzi sklep. –

2

Dobre odpowiedzi do tej pory. Same wyrażenia regularne są zwykle traktowane jako sposób dopasowywania wzorów, a nie generowania wyników w sposób, o którym wspomniałeś.

Powiedziawszy to, istnieje sposób użycia regex jako części rozwią[email protected] Jonathan Leffler napisał dobry komentarz do tster's reply: "... może potrzebujesz lepszej biblioteki regex w swoim języku."

W zależności od wybranego języka i dostępnej biblioteki, można ją usunąć. Na przykład przy użyciu C# i .NET można to osiągnąć za pomocą Regex.Replace method. Jednak rozwiązanie to nie 100% regex ponieważ nadal opiera się na innych klas i metod (StringBuilder, string.join i Enumerable.Repeat) jak pokazano poniżej:

string input = "aa67bc54c9"; 
string pattern = @"([a-z]+)(\d+)"; 
string result = Regex.Replace(input, pattern, m => 
     // can be achieved using StringBuilder or String.Join/Enumerable.Repeat 
     // don't use both 
     //new StringBuilder().Insert(0, m.Groups[1].Value, Int32.Parse(m.Groups[2].Value)).ToString() 
     String.Join("", Enumerable.Repeat(m.Groups[1].Value, Int32.Parse(m.Groups[2].Value)).ToArray()) 
     + Environment.NewLine // comment out to prevent line breaks 
     ); 
Console.WriteLine(result); 

Jaśniejsza rozwiązaniem byłoby zidentyfikowanie mecze , wykonaj pętlę nad nimi i wstaw je za pomocą StringBuilder zamiast polegać na Regex.Replace. Inne języki mogą mieć kompaktowe idiomy do obsługi mnożenia napisów, które nie opierają się na innych klasach bibliotek.

Aby odpowiedzieć na pytanie dotyczące wywiadu, odpowiedziałbym: "jest to możliwe, jednak rozwiązanie nie byłoby samodzielnym podejściem opartym na 100% wyrażeń regularnych i polegałoby na innych funkcjach językowych i/lub bibliotekach w celu radzenia sobie z aspektem generowania pytanie, ponieważ samo wyrażenie regularne jest pomocne w dopasowywaniu wzorców, a nie generowaniu ich. "

I na podstawie innych odpowiedzi tutaj, możesz w razie potrzeby uzupełnić tę odpowiedź.

+0

Znakomicie, jeśli osoba przeprowadzająca wywiad może to zrozumieć. –

Powiązane problemy