Làm cách nào để kiểm tra xem một chuỗi có phải là palindrome hay không bằng cách sử dụng biểu thức chính quy?


93

Đó là một câu hỏi phỏng vấn mà tôi không thể trả lời:

Làm cách nào để kiểm tra xem một chuỗi có phải là palindrome hay không bằng cách sử dụng biểu thức chính quy?

ps Đã có một câu hỏi " Làm thế nào để kiểm tra xem chuỗi đã cho có phải là palindrome hay không? " và nó đưa ra rất nhiều câu trả lời bằng các ngôn ngữ khác nhau, nhưng không có câu trả lời nào sử dụng biểu thức chính quy.


1
stackoverflow.com/questions/3644266/… có thể đưa ra ý tưởng.
Prakhar

2
Hiện tại (2018) và ai đang tìm kiếm "the palindrome regex", hãy xem thảo luận về PCRE hỗ trợ các mẫu đệ quy tại liên kết của Prakhar và regex đệ quy của tôi bên dưới, với các so sánh .
Peter Krauss

Câu trả lời:


151

Câu trả lời cho câu hỏi này là "điều đó là không thể". Cụ thể hơn, người phỏng vấn đang tự hỏi liệu bạn có chú ý đến lớp lý thuyết tính toán của mình hay không.

Trong lớp lý thuyết tính toán, bạn đã học về máy trạng thái hữu hạn. Một máy trạng thái hữu hạn bao gồm các nút và các cạnh. Mỗi cạnh được chú thích bằng một chữ cái trong bảng chữ cái hữu hạn. Một hoặc nhiều nút là nút "chấp nhận" đặc biệt và một nút là nút "bắt đầu". Khi mỗi chữ cái được đọc từ một từ nhất định, chúng tôi đi ngang qua cạnh nhất định trong máy. Nếu chúng ta kết thúc ở trạng thái chấp nhận thì chúng ta nói rằng máy "chấp nhận" từ đó.

Một biểu thức chính quy luôn có thể được dịch thành một máy trạng thái hữu hạn tương đương. Đó là, một ngôn ngữ chấp nhận và từ chối các từ tương tự như biểu thức chính quy (trong thế giới thực, một số ngôn ngữ regexp cho phép các hàm tùy ý, chúng không được tính).

Không thể xây dựng một cỗ máy trạng thái hữu hạn chấp nhận tất cả các palindromes. Chứng minh dựa trên các dữ kiện rằng chúng ta có thể dễ dàng xây dựng một chuỗi yêu cầu một số lượng lớn các nút tùy ý, cụ thể là chuỗi

a ^ xba ^ x (ví dụ: aba, aabaa, aaabaaa, aaaabaaaa, ....)

trong đó a ^ x là một lần lặp lại x lần. Điều này yêu cầu ít nhất x nút vì sau khi nhìn thấy chữ 'b', chúng ta phải đếm lại x lần để đảm bảo nó là palindrome.

Cuối cùng, quay lại câu hỏi ban đầu, bạn có thể nói với người phỏng vấn rằng bạn có thể viết một biểu thức chính quy chấp nhận tất cả các palindromes nhỏ hơn một số độ dài cố định hữu hạn. Nếu có một ứng dụng nào đó trong thế giới thực yêu cầu xác định các palindromes thì nó gần như chắc chắn sẽ không bao gồm các ứng dụng dài tùy ý, do đó câu trả lời này sẽ cho thấy rằng bạn có thể phân biệt những điều bất khả thi trên lý thuyết với các ứng dụng trong thế giới thực. Tuy nhiên, regexp thực tế sẽ khá dài, dài hơn nhiều so với chương trình 4 dòng tương đương (bài tập dễ dàng cho người đọc: viết một chương trình xác định các palindromes).


6
@SteveMoser Trong Ruby 1.9.x, các biểu thức chính quy không còn là Chính quy nữa (theo nghĩa Tự động hóa lý thuyết) và do đó, những việc như kiểm tra palindromes là có thể thực hiện được. Tuy nhiên, đối với ý định và mục đích, palindromes không thể được kiểm tra bằng regex Thông thường (hiểu không?).

1
@SteveMoser Có một writeup tốt của động cơ biểu hiện thường xuyên của Ruby ( >=1.9) ở đây

@John đúng, vậy trong bối cảnh câu hỏi Jose đúng và hqt sai.
Steve Moser

2
Về mặt học thuật, một biểu thức chính quy có các ranh giới cụ thể (xác định một DFA). Trên thực tế, nhiều công cụ regexp (chủ yếu là Perl và nó là họ hàng của nó) hỗ trợ backreferences vi phạm định nghĩa học thuật (trở thành NFA hoặc thậm chí rộng hơn). Vì vậy, câu hỏi này có các câu trả lời khác nhau tùy thuộc vào hệ quy chiếu của người hỏi.
jiggy

Trong một bài kiểm tra miệng, zou shoulsd đi với "formalz nó là không thể", nhưng bạn nên chỉ ra rằng một số động cơ regex cho phép điều đó.
Oliver A.

46

Mặc dù công cụ PCRE hỗ trợ các biểu thức chính quy đệ quy (xem câu trả lời của Peter Krauss ), bạn không thể sử dụng regex trên công cụ ICU (ví dụ như được sử dụng bởi Apple) để đạt được điều này mà không cần thêm mã. Bạn sẽ cần phải làm điều gì đó như sau:

Điều này phát hiện bất kỳ palindrome nào, nhưng yêu cầu một vòng lặp (sẽ được yêu cầu vì các biểu thức chính quy không thể đếm).

$a = "teststring";
while(length $a > 1)
{
   $a =~ /(.)(.*)(.)/;
   die "Not a palindrome: $a" unless $1 eq $3;
   $a = $2;
}
print "Palindrome";

4
Câu trả lời tốt. Câu hỏi không yêu cầu một regexp nào có thể phát hiện ra một palindrome ngay lập tức - nó chỉ yêu cầu một phương pháp phát hiện palindromes sử dụng regexps. Chúc mừng bạn đã có cái nhìn sâu sắc theo cách này.
Stewart

1
Xem thêm cách so khớp đơn giản nhất (không có thao tác chuỗi) chỉ sử dụng một regex, stackoverflow.com/a/48608623/287948
Peter Krauss

Cảm ơn @PeterKrauss. Không biết rằng PCRE có đệ quy. Đã tham khảo câu trả lời của bạn.
Airsource Ltd

32

Điều đó là không thể. Palindromes không được xác định bởi một ngôn ngữ thông thường. (Xem này, TÔI ĐÃ HỌC được điều gì đó trong lý thuyết tính toán)


2
Hầu hết các công cụ biểu thức chính quy nắm bắt nhiều hơn các ngôn ngữ thông thường (ví dụ: net có thể nắm bắt dấu ngoặc đơn phù hợp). Chỉ các regex tiêu chuẩn được giới hạn cho các ngôn ngữ thông thường.
Santiago Palladino

Tuy nhiên, câu hỏi đã sử dụng thuật ngữ "biểu thức chính quy" ... vì vậy câu trả lời của ZCHudson là đúng.
paxos1977 24/10/08

2
@austirg: Câu trả lời của ZCHudson đúng nhưng không đầy đủ. Biểu thức chính quy được sử dụng trong các ngôn ngữ lập trình hiện đại và biểu thức chính quy được sử dụng trong các lớp CS lý thuyết là những con thú khác nhau. Thuật ngữ chỉ là một di sản lịch sử. Xem stackoverflow.com/questions/233243#235199 và câu trả lời của tôi.
jfs

2
@JF Sebastian - Tôi phải đồng ý với Austirg về điều này. Khi thuật ngữ biểu thức chính quy được sử dụng mà không có ngôn ngữ lập trình cụ thể được đề cập hơn là áp dụng định nghĩa comp sci. Không phải tất cả các ngôn ngữ hỗ trợ regex đều có thể làm được điều này, vì vậy chúng ta không nên cho rằng ngôn ngữ được sử dụng ở đây làm được.
Rontologist

@Rontologist: Tôi không thấy hạn chế nào đối với việc lựa chọn ngôn ngữ lập trình trong câu hỏi, do đó bất kỳ ngôn ngữ nào cũng được phép. Nhìn bên phải: nghĩa của "biểu thức chính quy" trong các câu hỏi liên quan là gì? Ngôn ngữ lập trình cụ thể có được đề cập trong bất kỳ ngôn ngữ lập trình nào không?
jfs

27

Với Perl regex:

/^((.)(?1)\2|.?)$/

Mặc dù, như nhiều người đã chỉ ra, đây không thể được coi là một biểu thức chính quy nếu bạn muốn nghiêm ngặt. Biểu thức chính quy không hỗ trợ đệ quy.


điều này không hoạt động trong PCRE (nó không khớp với "ababa"), nhưng nó hoạt động trong Perl 5.10
newacct

Bạn đúng rồi. PCRE dường như coi đệ quy như một nhóm nguyên tử, trong khi Perl cho phép bẻ khóa ngược bên trong nó. Tôi không nghĩ có thể thực hiện việc kiểm tra này tại PCRE.
Markus Jarderot

1
Đáng ngạc nhiên, không hoạt động đối với các ngôn ngữ không phải Latinh, ví dụ như ngôn ngữ Armenia.
Temujin

3
@Temujin Có thể là do các ký tự unicode được khớp dưới dạng các byte được mã hóa (thêm công cụ /usửa đổi ) hoặc do các ký tự tổ hợp. (thay thế .bằng \Xtrình tự thoát ).
Markus Jarderot

1
Mẫu của tôi không hoạt động trong PCRE. Nó hoạt động ở Perl. Mẫu của bạn không thành công khi các chuỗi con được lặp lại. Ví dụ abababa. Không thể làm cho nó hoạt động với đệ quy cho mọi đầu vào khi sử dụng công cụ regex dựa trên PCRE. Casimirs regex sử dụng một cách tiếp cận khác, sử dụng trạng thái lặp lại và có thể thay đổi, và khá hấp dẫn.
Markus Jarderot

15

Đây là một để phát hiện các palindromes 4 chữ cái (ví dụ: chứng thư), cho bất kỳ loại ký tự nào:

\(.\)\(.\)\2\1

Đây là một để phát hiện các palindromes 5 chữ cái (ví dụ: radar), chỉ kiểm tra các chữ cái:

\([a-z]\)\([a-z]\)[a-z]\2\1

Vì vậy, có vẻ như chúng ta cần một regex khác nhau cho mỗi độ dài từ có thể. Bài đăng này trên danh sách gửi thư Python bao gồm một số chi tiết về lý do (Dữ liệu tự động hóa trạng thái hữu hạn và bổ đề bơm).


14

Tùy thuộc vào mức độ tự tin của bạn, tôi sẽ đưa ra câu trả lời sau:

Tôi sẽ không làm điều đó với một biểu thức chính quy. Đây không phải là cách sử dụng thích hợp các biểu thức chính quy.


3
Tôi hy vọng bạn sẽ giải thích thêm một chút để chứng tỏ rằng bạn thực sự hiểu những hạn chế của regex. Câu trả lời đơn giản của bạn có thể được coi là "Tôi bối rối".
Scott Wegner

Do đó mệnh đề phụ thuộc anh ta đưa ra.
Will Bickford

13

, bạn có thể làm điều đó trong .Net!

(?<N>.)+.?(?<-N>\k<N>)+(?(N)(?!))

Bạn có thể kiểm tra nó ở đây ! Đó là một bài viết tuyệt vời!


Toàn bộ điểm của .NET có hương vị Regex là chúng không thường xuyên vì chúng không phải là một tự động trạng thái hữu hạn; chúng không thực sự regex theo nghĩa lý thuyết.
con mèo

12

StackOverflow chứa đầy các câu trả lời như "Cụm từ thông dụng? Nope, họ không hỗ trợ. Họ không thể hỗ trợ.".

Sự thật là cụm từ thông dụng không liên quan gì đến ngữ pháp thông thường nữa. Biểu thức chính quy hiện đại có các chức năng như nhóm đệ quy và cân bằng và tính khả dụng của các triển khai của chúng ngày càng tăng (ví dụ: xem các ví dụ về Ruby ở đây). Theo quan điểm của tôi, việc dựa vào niềm tin cũ rằng các biểu thức chính quy trong lĩnh vực của chúng ta là bất cứ thứ gì ngoài một khái niệm lập trình chỉ là phản tác dụng. Thay vì ghét bỏ họ vì lựa chọn từ ngữ không còn phù hợp nhất, đã đến lúc chúng ta nên chấp nhận mọi thứ và bước tiếp.

Đây là câu nói của Larry Wall , người tạo ra Perl:

(…) Thường liên quan đến những gì chúng ta gọi là “biểu thức chính quy”, chỉ có liên quan một chút đến biểu thức chính quy thực. Tuy nhiên, thuật ngữ này đã phát triển với khả năng của các công cụ đối sánh mẫu của chúng tôi, vì vậy tôi sẽ không cố gắng chống lại sự cần thiết về ngôn ngữ ở đây. Tuy nhiên, tôi thường gọi chúng là “regexes” (hoặc “regexen”, khi tôi ở trong tâm trạng Anglo-Saxon).

Và đây là một bài đăng trên blog của một trong những nhà phát triển cốt lõi của PHP :

Vì bài viết khá dài, đây là tóm tắt các điểm chính:

  • Các "biểu thức chính quy" được các lập trình viên sử dụng có rất ít điểm chung với khái niệm ban đầu về tính đều đặn trong ngữ cảnh lý thuyết ngôn ngữ chính thức.
  • Cụm từ thông dụng (ít nhất là PCRE) có thể khớp với tất cả các ngôn ngữ không có ngữ cảnh. Như vậy, chúng cũng có thể khớp với HTML được định dạng tốt và khá nhiều ngôn ngữ lập trình khác.
  • Cụm từ thông dụng có thể khớp với ít nhất một số ngôn ngữ nhạy cảm theo ngữ cảnh.
  • Đối sánh các biểu thức chính quy là NP-đầy đủ. Như vậy, bạn có thể giải quyết bất kỳ vấn đề NP nào khác bằng cách sử dụng biểu thức chính quy.

Điều đó đang được nói, bạn có thể so khớp palindromes với regexes bằng cách sử dụng:

^(?'letter'[a-z])+[a-z]?(?:\k'letter'(?'-letter'))+(?(letter)(?!))$

... rõ ràng không liên quan gì đến ngữ pháp thông thường.
Thông tin thêm tại đây: http://www.regular-expressions.info/balancing.html


9

Như một số người đã nói, không có một regexp nào có thể phát hiện ra bệnh palindrome chung, nhưng nếu bạn muốn phát hiện bệnh palindrom ở một độ dài nhất định, bạn có thể sử dụng một số thứ như

(.?)(.?)(.?)(.?)(.?).?\5\4\3\2\1

7

Nó có thể được thực hiện ở Perl ngay bây giờ. Sử dụng tham chiếu đệ quy:

if($istr =~ /^((\w)(?1)\g{-1}|\w?)$/){
    print $istr," is palindrome\n";
}

được sửa đổi dựa trên phần gần cuối http://perldoc.perl.org/perlretut.html


6

Trong ruby, bạn có thể sử dụng các nhóm chụp được đặt tên. vì vậy một cái gì đó như thế này sẽ hoạt động -

def palindrome?(string)
  $1 if string =~ /\A(?<p>| \w | (?: (?<l>\w) \g<p> \k<l+0> ))\z/x
end

hãy thử nó, nó hoạt động ...

1.9.2p290 :017 > palindrome?("racecar")
 => "racecar" 
1.9.2p290 :018 > palindrome?("kayak")
 => "kayak" 
1.9.2p290 :019 > palindrome?("woahitworks!")
 => nil 

1
Các nhóm bắt được đặt tên không hoàn toàn là regex. willamette.edu/~fruehr/LLC/lab5.html
Steve Moser

2
Bạn nói đúng. Đó là lý do cụ thể tại sao tôi đã chỉ ra rằng bạn sẽ phải sử dụng các nhóm chụp được đặt tên.
Taylor

Ai đó có thể tình cờ giải thích ký tự RE đó theo từng ký tự cho người mới không? Tôi hiểu tất cả những điều sau (dấu phẩy phân tách các 'nguyên tử') /, \ A, (, |, \ w, |, (, (, \ w,),),), \ z, /, x nhưng tôi không hiểu 'không hiểu bất kỳ điều nào trong số này? <p>,?:,? <l>, \ g <p>, \ k <l + 0> và tôi đang sử dụng rubular.com để được trợ giúp và có vẻ như nó hiểu RE ( tự nhiên), nhưng điều đó không giúp tôi nhìn thấy nó, và thậm chí "Để có hướng dẫn hoàn chỉnh về Ruby regex, hãy xem Pickaxe." không giúp ích được gì, vì trang web được liên kết với 'Pickaxe' không giải thích các nguyên tử mà tôi không hiểu. Tôi biết ? THEO DÕI một phù hợp với Zero hoặc một trong số a, nhưng? đứng trước một ký tự?
Kevin Ford tàu ngầm

Ah, các nhóm bắt tên ! Đẹp. @SteveMoser hiện là một liên kết bị hỏng, nhưng tôi đã tìm thấy một liên kết khác . Cảm ơn Taylor đã đề cập đến họ, nếu không, tôi sẽ không biết nghĩa là gì? <p> và? <l> và?: (Nhóm chụp không chụp) và \ g <p> và \ k <l + 0>. Tôi vẫn không thấy gì? <p> | là mặc dù. Không | nghĩa là "hoặc"? Tôi không thể tìm thấy tài liệu về cách sử dụng đường ống đó trong REs. Tôi vẫn rất vui khi thấy một lời giải thích chi tiết cho RE rất hay này.
Kevin Ford chiếc tàu ngầm

5

Nó thực sự dễ dàng hơn để làm điều đó với thao tác chuỗi thay vì các biểu thức thông thường:

bool isPalindrome(String s1)

{

    String s2 = s1.reverse;

    return s2 == s1;
}

Tôi nhận ra rằng điều này không thực sự trả lời câu hỏi phỏng vấn, nhưng bạn có thể sử dụng nó để chỉ ra cách bạn biết cách thực hiện nhiệm vụ tốt hơn và bạn không phải là người điển hình "cầm búa, coi mọi vấn đề như đinh đóng cột" . "


Trong khi tôi khá thích câu trả lời này, tôi nghĩ rằng bạn sẽ nhận được thêm điểm bằng cách sử dụng BreakIterator để chia chuỗi thành các ký tự trực quan một cách chính xác.
Trejkaz

5

Đây là câu trả lời của tôi cho cấp độ thứ 5 của Regex Golf (Một người đàn ông, một kế hoạch). Nó hoạt động với tối đa 7 ký tự với Regexp của trình duyệt (Tôi đang sử dụng Chrome 36.0.1985.143).

^(.)(.)(?:(.).?\3?)?\2\1$

Đây là một cho tối đa 9 ký tự

^(.)(.)(?:(.)(?:(.).?\4?)?\3?)?\2\1$

Để tăng số ký tự tối đa mà nó hoạt động, bạn sẽ thay thế nhiều lần .? với (?: (.).? \ n?)? .


1
Tôi quản lý cái đó với ít ký tự hơn một chút, ^ (.) (.) (.)?.? \ 3 \ 2 \ 1 $
Ben Ellis

Cảm ơn rất nhiều vì đã làm hỏng nó cho tôi :-)
U10-Chuyển tiếp

Tại sao những người còn lại có 13 nhưng đây là 19
U10-Chuyển tiếp

5

Biểu thức chính quy đệ quy có thể làm được điều đó!

Thuật toán đơn giản và hiển nhiên để phát hiện một chuỗi có chứa palindrome:

   (\w)(?:(?R)|\w?)\1

Tại rexegg.com/regex-recursion , hướng dẫn giải thích cách nó hoạt động.


Nó hoạt động tốt với bất kỳ ngôn ngữ nào, đây là một ví dụ được điều chỉnh từ cùng một nguồn (liên kết) làm bằng chứng khái niệm, sử dụng PHP:

$subjects=['dont','o','oo','kook','book','paper','kayak','okonoko','aaaaa','bbbb'];
$pattern='/(\w)(?:(?R)|\w?)\1/';
foreach ($subjects as $sub) {
  echo $sub." ".str_repeat('-',15-strlen($sub))."-> ";
  if (preg_match($pattern,$sub,$m)) 
      echo $m[0].(($m[0]==$sub)? "! a palindrome!\n": "\n");
  else 
      echo "sorry, no match\n";
}

đầu ra

dont ------------> sorry, no match
o ---------------> sorry, no match
oo --------------> oo! a palindrome!
kook ------------> kook! a palindrome!
book ------------> oo
paper -----------> pap
kayak -----------> kayak! a palindrome!
okonoko ---------> okonoko! a palindrome!
aaaaa -----------> aaaaa! a palindrome!
bbbb ------------> bbb

So sánh

Biểu thức chính quy ^((\w)(?:(?1)|\w?)\2)$ thực hiện công việc tương tự, nhưng thay vào đó là yes / not là "chứa".
Tái bút: nó đang sử dụng một định nghĩa trong đó "o" không phải là palimbrome, định dạng gạch nối "could-elba" không phải là palindrome, mà là "canelba". Đặt tên định nghĩa cho nó1 .
Khi "o" và "could-elba" là palindrones, định nghĩa đặt tên2 .

So sánh với một "palindrome regexes" khác,

  • ^((.)(?:(?1)|.?)\2)$base-regex ở trên mà không \wbị hạn chế, chấp nhận "could-elba".

  • ^((.)(?1)?\2|.)$( @LilDevil ) Sử dụng định nghĩa2 (chấp nhận "o" và "could-elba", do đó cũng khác nhau trong việc nhận dạng các chuỗi "aaaaa" và "bbbb").

  • ^((.)(?1)\2|.?)$( @Markus ) không phát hiện thấy "kook" cũng như "bbbb"

  • ^((.)(?1)*\2|.?)$( @Csaba ) Sử dụng định nghĩa2 .


LƯU Ý: để so sánh, bạn có thể thêm nhiều từ hơn tại $subjectsvà một dòng cho mỗi regex được so sánh,

  if (preg_match('/^((.)(?:(?1)|.?)\2)$/',$sub)) echo " ...reg_base($sub)!\n";
  if (preg_match('/^((.)(?1)?\2|.)$/',$sub)) echo " ...reg2($sub)!\n";
  if (preg_match('/^((.)(?1)\2|.?)$/',$sub)) echo " ...reg3($sub)!\n";
  if (preg_match('/^((.)(?1)*\2|.?)$/',$sub)) echo " ...reg4($sub)!\n";

5

Bạn cũng có thể làm điều đó mà không cần sử dụng đệ quy:

\A(?:(.)(?=.*?((?(2)\1\2|\1))\z))*?.?\2\z

để cho phép một ký tự:

\A(?:(?:(.)(?=.*?((?(2)\1\2|\1))\z))*?.?\2|.)\z

Làm việc với Perl, PCRE

bản giới thiệu

Đối với Java:

\A(?:(.)(?=.*?(\1\2\z|(?<!(?=\2\z).{0,1000})\1\z)))*?.?\2\z

bản giới thiệu


1
Đây là một câu trả lời rất thú vị cho một câu hỏi regex. Trên thực tế, mẫu duy nhất đã vượt qua một số bài kiểm tra của tôi . Cảm ơn vì điều này Casimir :)
bobble bubble.

1
@bobblebubble: Cảm ơn sự hỗ trợ của bạn. Như bạn có thể thấy, tôi đã chỉnh sửa câu trả lời này gần đây vì phiên bản trước đó đã sai (trong ba năm, thật đáng tiếc).
Casimir et Hippolyte

4

Về biểu thức PCRE (từ MizardX):

/^((.)(?1)\2|.?)$/

Bạn đã thử nghiệm nó chưa? Trên PHP 5.3 của tôi trong Win XP Pro, nó không thành công trên: aaaba Thực ra, tôi đã sửa đổi biểu thức biểu thức một chút, để đọc:

/^((.)(?1)*\2|.?)$/

Tôi nghĩ những gì đang xảy ra là trong khi cặp nhân vật bên ngoài được cố định, những người bên trong còn lại thì không. Đây không phải là toàn bộ câu trả lời bởi vì trong khi nó chuyển sai "aaaba" và "aabaacaa", nó không chính xác trên "aabaaca".

Tôi tự hỏi liệu có bản sửa lỗi cho điều này, và ví dụ Perl (của JF Sebastian / Zsolt) có vượt qua các bài kiểm tra của tôi một cách chính xác không?

Csaba Gabor từ Vienna



3

Trong Perl (xem thêm câu trả lời của Zsolt Botykai ):

$re = qr/
  .                 # single letter is a palindrome
  |
  (.)               # first letter
  (??{ $re })??     # apply recursivly (not interpolated yet)
  \1                # last letter
/x;

while(<>) {
    chomp;
    say if /^$re$/; # print palindromes
}

2

Như đã chỉ ra bởi ZCHudson , hãy xác định xem điều gì đó có phải là palindrome không thì không thể thực hiện được với regexp thông thường, vì tập hợp palindrome không phải là ngôn ngữ thông thường.

Tôi hoàn toàn không đồng ý với Airsource Ltd khi anh ấy nói rằng "nó không có khả năng" không phải là loại câu trả lời mà người phỏng vấn đang tìm kiếm. Trong cuộc phỏng vấn của mình, tôi đặt ra loại câu hỏi này khi đối mặt với một ứng viên giỏi, để kiểm tra xem liệu anh ta có thể tìm ra lý lẽ đúng đắn khi chúng tôi đề nghị anh ta làm sai điều gì đó không. Tôi không muốn thuê một người sẽ cố gắng làm điều gì đó sai trái nếu anh ta biết tốt hơn.



2

Tôi sẽ giải thích với người phỏng vấn rằng ngôn ngữ bao gồm palindromes không phải là ngôn ngữ thông thường mà thay vào đó là ngôn ngữ không có ngữ cảnh.

Biểu thức chính quy phù hợp với tất cả các palindromes sẽ là vô hạn . Thay vào đó, tôi sẽ đề nghị anh ta hạn chế bản thân ở một kích thước tối đa của palindromes để chấp nhận; hoặc nếu tất cả các palindromes đều cần sử dụng tối thiểu một số loại NDPA hoặc chỉ sử dụng kỹ thuật đảo ngược / bằng chuỗi đơn giản.


2

Điều tốt nhất bạn có thể làm với regexes, trước khi hết nhóm chụp:

/(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\9\8\7\6\5\4\3\2\1/

Điều này sẽ khớp với tất cả các palindromes có độ dài tối đa 19 ký tự.

Việc giải quyết theo chương trình cho tất cả các độ dài là điều nhỏ nhặt:

str == str.reverse ? true : false

Regex của bạn không hoạt động. Ví dụ, nó sẽ chỉ ra rằng "ABAC" là một trận đấu ...
Darwin Airola

2

Tôi chưa có đại diện để bình luận nội tuyến, nhưng regex do MizardX cung cấp và được Csaba sửa đổi, có thể được sửa đổi thêm để làm cho nó hoạt động trong PCRE. Lỗi duy nhất tôi đã tìm thấy là chuỗi ký tự đơn, nhưng tôi có thể kiểm tra điều đó một cách riêng biệt.

/^((.)(?1)?\2|.)$/

Nếu bạn có thể làm cho nó không thành công trên bất kỳ chuỗi nào khác, vui lòng nhận xét.


2
#!/usr/bin/perl

use strict;
use warnings;

print "Enter your string: ";
chop(my $a = scalar(<STDIN>));    
my $m = (length($a)+1)/2;
if( (length($a) % 2 != 0 ) or length($a) > 1 ) { 
  my $r; 
  foreach (0 ..($m - 2)){
    $r .= "(.)";
  }
  $r .= ".?";
  foreach ( my $i = ($m-1); $i > 0; $i-- ) { 
    $r .= "\\$i";
  } 
  if ( $a =~ /(.)(.).\2\1/ ){
    print "$a is a palindrome\n";
  }
  else {
    print "$a not a palindrome\n";
 }
exit(1);
}
print "$a not a palindrome\n";

2

Từ lý thuyết tự động, nó không thể khớp với một paliandrome của bất kỳ độ dài nào (vì điều đó đòi hỏi lượng bộ nhớ vô hạn). Nhưng NÓ CÓ KHẢ NĂNG phù hợp với Paliandromes có độ dài cố định. Giả sử có thể viết một regex khớp với tất cả các paliandrom có ​​độ dài <= 5 hoặc <= 6, nhưng không> = 5, v.v. trong đó giới hạn trên không rõ ràng


2

Trong Ruby, bạn có thể sử dụng \b(?'word'(?'letter'[a-z])\g'word'\k'letter+0'|[a-z])\bđể ghép các từ palindrome chẳng hạn như a, dad, radar, racecar, and redivider. ps: regex này chỉ phù hợp với các từ palindrome có độ dài là một số lẻ các chữ cái.

Hãy xem regex này khớp với radar như thế nào. Ranh giới từ \ b khớp ở đầu chuỗi. Công cụ regex đi vào nhóm chụp "từ". [az] khớp với r mà sau đó được lưu trữ trong ngăn xếp cho "chữ cái" của nhóm thu thập ở cấp đệ quy 0. Bây giờ công cụ regex nhập đệ quy đầu tiên của nhóm "từ". (? 'letter' [az]) đối sánh và nắm bắt một ở cấp đệ quy một. Regex nhập đệ quy thứ hai của nhóm "từ". (? 'letter' [az]) bắt d ở mức đệ quy hai. Trong hai lần đệ quy tiếp theo, nhóm ghi lại a và r ở cấp độ ba và bốn. Đệ quy thứ năm không thành công vì không còn ký tự nào trong chuỗi để [az] khớp. Công cụ regex phải quay lại.

Công cụ regex bây giờ phải thử giải pháp thay thế thứ hai bên trong nhóm "từ". [Az] thứ hai trong regex khớp với r cuối cùng trong chuỗi. Giờ đây, động cơ sẽ thoát khỏi một lần đệ quy thành công, đi ngược một cấp lên đệ quy thứ ba.

Sau khi đối sánh (& từ), công cụ đạt đến \ k'letter + 0 '. Tham khảo ngược không thành công vì công cụ regex đã đến cuối chuỗi chủ đề. Vì vậy, nó quay lại một lần nữa. Phương án thứ hai phù hợp với a. Công cụ regex thoát khỏi đệ quy thứ ba.

Công cụ regex đã khớp (& word) một lần nữa và cần thử tham khảo lại. Backreference chỉ định +0 hoặc mức đệ quy hiện tại, là 2. Ở mức này, nhóm thu thập đã khớp d. Tham khảo ngược không thành công vì ký tự tiếp theo trong chuỗi là r. Backtracking một lần nữa, thay thế thứ hai phù hợp với d.

Bây giờ, \ k'letter + 0 'khớp với a thứ hai trong chuỗi. Đó là bởi vì công cụ regex đã quay trở lại lần đệ quy đầu tiên trong đó nhóm thu nhận khớp với lần đầu tiên a. Công cụ regex thoát khỏi đệ quy đầu tiên.

Công cụ regex bây giờ đã trở lại bên ngoài tất cả đệ quy. Đó là mức này, nhóm thu thập được lưu trữ r. Tham chiếu ngược bây giờ có thể khớp với r cuối cùng trong chuỗi. Vì engine không còn bên trong bất kỳ đệ quy nào nữa, nên nó tiếp tục với phần còn lại của regex sau nhóm. \ b khớp ở cuối chuỗi. Kết thúc của regex đã đạt đến và radar được trả lại như trận đấu tổng thể.


2

đây là mã PL / SQL cho biết chuỗi đã cho có phải là palindrome hay không sử dụng biểu thức chính quy:

create or replace procedure palin_test(palin in varchar2) is
 tmp varchar2(100);
 i number := 0;
 BEGIN
 tmp := palin;
 for i in 1 .. length(palin)/2 loop
  if length(tmp) > 1 then  
    if regexp_like(tmp,'^(^.).*(\1)$') = true then 
      tmp := substr(palin,i+1,length(tmp)-2);
    else 
      dbms_output.put_line('not a palindrome');
      exit;
    end if;
  end if;  
  if i >= length(palin)/2 then 
   dbms_output.put_line('Yes ! it is a palindrome');
  end if;
 end loop;  
end palin_test;

2
my $pal='malayalam';

while($pal=~/((.)(.*)\2)/){                                 #checking palindrome word
    $pal=$3;
}
if ($pal=~/^.?$/i){                                         #matches single letter or no letter
    print"palindrome\n";
}
else{
    print"not palindrome\n";
}

2
Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh về cách và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Vịt Donald

2

Regex này sẽ phát hiện các palindromes lên đến 22 ký tự bỏ qua dấu cách, tab, dấu phẩy và dấu ngoặc kép.

\b(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*(?:(\w)[ \t,'"]*\11?[ \t,'"]*\10|\10?)[ \t,'"]*\9|\9?)[ \t,'"]*\8|\8?)[ \t,'"]*\7|\7?)[ \t,'"]*\6|\6?)[ \t,'"]*\5|\5?)[ \t,'"]*\4|\4?)[ \t,'"]*\3|\3?)[ \t,'"]*\2|\2?))?[ \t,'"]*\1\b

Chơi với nó tại đây: https://regexr.com/4tmui


0

Một chút cải tiến về phương pháp của Airsource Ltd, trong mã giả:

WHILE string.length > 1
    IF /(.)(.*)\1/ matches string
        string = \2
    ELSE
        REJECT
ACCEPT
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.