# Shortest code to determine if a string is a palindrome

A palindrome is some string that is spelled the same way both backwards and forwards. For instance, 'Eva, can I stab bats in a cave?' is a palindrome (EVACANISTAB | BATSINACAVE)

For this code golf, using the language of your choice, determine if a given string is a palindrome or not.

Edge Cases:

• Punctuation is not counted towards palindrominess.
• Control characters are not counted towards palindrominess.
• Whitespace is not counted towards palindrominess.
• Numbers are counted towards palindrominess.
• Case in this challenge is not counted towards palindrominess.
• There is no limit to the length of strings to evaluate, except for what is imposed by your language of choice.
• For this challenge, limit yourself to the ASCII character set.

Technical Requirements:

• Only method bodies are needed; additional things like method signatures, data structure declarations, etc. do not count towards the victory requirement.
• Code must compile or interpret without compile-time errors or exceptions.
• Code must not throw any unhandled exceptions or crash. (Almost needless to say. Almost.)
• Code must return some value indicating palindrominess. The data type depends on the language you use (e.g. a C# user might use a bool, whereas a JavaScript user could use a var.)
• You may not write your own interpreter that performs this task as a 'native' capability so you can 'golf' a near-winning score. (Hopefully needless to say.)

Victory Condition:

• The shortest code in characters wins.

# Current Leader: tmartin (k, 25 characters)

• Is I/O a part of the challenge, or a function body will do? – John Dvorak Apr 8 '13 at 18:43
• The "breadcrumbs" for showing how the work is refined are available site-wide in all answers via revision history. There's no need to have a full history visible in the current version of the answer. – Peter Taylor Apr 8 '13 at 20:27
• @WernerCD I'm sure the OP will change who gets the green tick when he comes back to check on the new responses. – Gareth Apr 9 '13 at 7:15
• Not specifying a language really trivialises this challenge for me. As seen below, interpreted languages with a focus on high order text manipulation functions always get the shortest results. What is to stop me throwing together my own interpreter with a single function, ip(). My compete algorithm is now 'ip:i'. 4 characters. done. – Gusdor Apr 9 '13 at 8:11
• @Gusdor see J and GolfScript suck all the enjoyment out of Code Golf and Language Handicap and related questions on this site's meta. – AakashM Apr 9 '13 at 8:25

## K, 25

{x~|x:_x@&x in,/.QaAn}

.

k){x~|x:_x@&x in,/.QaAn}"Eva, can I stab bats in a cave?"
1b
• Looks like a mixture of Q and k :P – skeevey Apr 9 '13 at 12:29
• Well, I wouldn't exactly call .Q.A etc q. They're just string wrappers, there's no real k code underneath them. Now, if I said .q.inter I'd be in trouble. – tmartin Apr 9 '13 at 12:45
• I guess it's a case of quibbling over semantics but they are defined in q.k – skeevey Apr 9 '13 at 12:54
• Could just say Q for 31: {x~(|)x:(_)x inter(,/).QaAn} – tmartin Apr 9 '13 at 13:03
• i know this is very old but... you can save 1 byte with {#|:\_x@&x in,/.QaAn} , where 1 is true and 2 is false – scrawl Oct 24 '19 at 14:14

## Perl, 26 char

s/_|\W//g;uc eq reverse uc

Evaluates to 1 when $_ is a palindrome, "" (one of Perl's false values) when it is not. Sample usage: sub palin { s/_|\W//g;uc eq reverse uc } while (<DATA>) { chomp; print "$_ => ",palin()?"yes":"no","\n";
}
__DATA__
Eva, can I stab bats in a cave?
A man, a plan, a canal. Panama!
757
Boeing 757
A man, a plan, a big shovel, a canal. Panama!
A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal >> __Panama__

output:

Eva, can I stab bats in a cave? => yes
A man, a plan, a canal. Panama! => yes
757 => yes
Boeing 757 => no
A man, a plan, a big shovel, a canal. Panama! => no
A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal >> __Panama__ => yes
• Damn, you beat me to it. Though this won't work properly if there's a _ in the string will it? And it doesn't take any input so won't you need to use the -p option? – Gareth Apr 8 '13 at 22:35
• \W in regexes excludes underscore. I'm afraid you'll need [^a-z\d] in your regex. I'm afraid I'm beaten anyways. – John Dvorak Apr 8 '13 at 22:37
• Save one with _|\W instead of [_\W]. – Howard Apr 9 '13 at 9:20
• You can shorten _|\W to \Pl: ideone.com/0ufdaQ . Should be just the Unicode letters. – Kobi Apr 10 '13 at 7:13
• Actually, thinking again - \Pl would not match digits, so I guess _|\W is the best you could do. – Kobi Apr 10 '13 at 9:59

### C# 82 only :)

var x=s.ToLower().Where(char.IsLetterOrDigit);return x.SequenceEqual(x.Reverse());

Couldn't resist the temptation of writing a boilerplate-free program in my favorite language.

A test is available here: http://ideone.com/8bwz7z

• Simple...but elegant! – Andrew Gray Apr 8 '13 at 20:21
• @AndrewGray thank you for the comment and for the permissive Technical Requirements. C# boilerplate adds seriously to the char count, making it impractical for golf otherwise. – Cristian Lupascu Apr 8 '13 at 20:31
• No prob. I'm a fellow C# dev, and I like writing concise, efficient code. It's a shame there's so much boilerplate in the language... – Andrew Gray Apr 8 '13 at 21:13

### GolfScript, 36 34 31 30 characters

{0"0:A[a{"@{>^}+/},{32|}%.-1%=

Similar algorithm to my previous (Javascript) solution.

0"0:A[a{"@{>^}+/ -- Optimised by Peter Taylor and Howard. My version was "/9@Z"{1$<},,2%\;. Howard donated function concatenation and Peter Taylor donated XOR for modulo-2. It's basically a generic method of comparing if the value is in a sequence of ranges. {.96>32*-}% (11 characters) is not really an improvement over Javascript's .toUpperCase() (14 characters), especially since it mangles some weird punctuation that follows z in the ASCII table (which doesn't matter here). as Peter Taylor's suggested, however, if we filter out alphanumerics first, we can convert to lowercase and digits just by setting one bit in each character: {32|} .-1%= does all the palindromic heavy lifting. One part I'm not really fond of is how long it took me to find out how to reverse an array. I should have read the docs. The other two characters perform stack management and comparison. Further, if I can assume that none of the following control characters are present: (Data link escape, device control 1-4, negative acknowledge, synchronous idle, end of transmission block, cancel, end of medium) (we all agree these are all pretty obscure) or if I can treat them as uppercase versions of the digits 0-9, we can save another two characters: ## GolfScript, 28 characters {32|}%{0"0:a{"@{>^}+/},.-1%= • You can get rid of the clean up and save two chars: {"0:A["\{>}+,,2%}, – Howard Apr 8 '13 at 21:01 • @Howard Thanks. I think I misunderstood + on blocks. That's a cool trick. – John Dvorak Apr 8 '13 at 21:08 • You can save three chars by reversing the filter and the case standardisation. You have to add a{ to the filter's list of characters to include the lower-case letters, but you can then upper-case with just {32|}%. The end result is {"0:A[a{"\{>}+,,2%},{32|}%.-1%= – Peter Taylor Apr 10 '13 at 23:09 • There also another saving to be made on the filter. Counting modulo 2 is xor, so 0"0:A[a{"@{>^}+/ does the job. – Peter Taylor Apr 11 '13 at 8:13 • @PeterTaylor If I don't come up with another optimisation myself soon, I probably should convert to community wiki. Thanks again :-) – John Dvorak Apr 11 '13 at 8:36 ### Javascript, 53 characters: (x=x.toLowerCase().match(/[a-z\d]/g))+""==x.reverse() is a javascript expression that evaluates to true if x is a palindrome, to false if it isn't. It assumes x is a string. If that's not guaranteed, prepend x+="", Here's a breadcrumb: Due to how reverse() works, (x=x.toLowerCase().match(/[a-z\d]/g))==""+x.reverse() fails. However, ""+(x=x.toLowerCase().match(/[a-z\d]/g))==x.reverse() is perfectly fine. • Nice tidbit on concatenating a null string! Points for good infoz! – Andrew Gray Apr 8 '13 at 19:35 • Hints: +"" casts to a string, + casts to a number, |0 and ~~ cast to an integer, !! casts to a boolean. – John Dvorak Apr 8 '13 at 19:37 • Is a char shorter with regex /[^\W_]/g – SuperPrograman Dec 6 '15 at 21:36 ## R: 66 w=grep("[a-z0-9]",strsplit(tolower(s),"")[[1]],v=T);all(w==rev(w)) Usage: f=function(s){w=grep("[a-z0-9]",strsplit(tolower(s),"")[[1]],v=T);all(w==rev(w))} f("Eva, can I stab bats in a cave?") [1] TRUE # Bash: 5248 46 characters s=${1,,};s=${s//[^a-z0-9]};[$s = rev<<<$s ] This takes the sting to check as first parameter and sets the exit code to 0 for palindrome and 1 for not. Sample run: bash-4.2$ p() { s=${1,,};s=${s//[^a-z0-9]};[ $s = rev<<<$s ]; }

bash-4.2$p 'Eva, can I stab bats in a cave?'; echo$?
0

bash-4.2$p 'A man, a plan, a canal. Panama!'; echo$?
0

bash-4.2$p "Madam, I'm Adam Corolla."; echo$?
1

bash-4.2$p '757'; echo$?
0

bash-4.2$p 'Boeing 757'; echo$?
1

bash-4.2$p 'A man, a plan, a shovel, a canal. Panama!'; echo$?
1

bash-4.2$p 'A_man,_a_plan, a_caremer, a canal:_Panama!'; echo$?
0

Python 2: 49 (without counting the method signature)

def f(s):
s=filter(str.isalnum,s.upper())
return s==s[::-1]

A complete program, with input and output can be writte in 74 characters.

import sys
print s==s[::-1]

Example usage:

$echo 'Eva,can I stab bats in a cave?' | python palindrome.py True$ cat huge_palindrome.txt | python palindrome.py
True

Example:

k){X~|X@:&(X:_:x)in 10h$(48+!10),97+!26} "Eva, can I stab bats in a cave?" 1b edit: shaved three more character by avoiding intermediate variable. H/T, CS. -7: No need to suppress errors. • interesting that at just 3 characters more, my code is much more readable :-) – John Dvorak Apr 8 '13 at 19:38 • An extra char slipped in, I have removed it. – skeevey Apr 8 '13 at 19:42 # Ruby: 43 38 characters s=s.upcase.tr'^A-Z0-9','';s==s.reverse Sample run: irb(main):001:0> p=->s{s=s.upcase.tr'^A-Z0-9','';s==s.reverse} => #<Proc:0x854592c@(irb):1 (lambda)> irb(main):002:0> p['Eva, can I stab bats in a cave?'] => true irb(main):003:0> p['A man, a plan, a canal. Panama!'] => true irb(main):004:0> p["Madam, I'm Adam Corolla."] => false irb(main):005:0> p['757'] => true irb(main):006:0> p['Boeing 757'] => false irb(main):007:0> p['A man, a plan, a shovel, a canal. Panama!'] => false irb(main):009:0> p['A_man,_a_plan, a_caremer, a canal:_Panama!'] => true • You can even write s.tr!('^A-Za-z0-9','').upcase!.reverse==s – Howard Apr 9 '13 at 9:19 • Man, how long I combined around the use of the ! methods! You keep amazing me @Howard with your tricks. – manatwork Apr 9 '13 at 9:41 • Small problem though, @Howard. tr and tr! seems to behave different when they have nothing to transliterate: pastebin.com/4YThW2qN That makes the p['757'] test to crash with “NoMethodError: undefined method upcase!' for nil:NilClass” error. – manatwork Apr 9 '13 at 9:53 • Oops, sorry. Didn't think about that case. – Howard Apr 9 '13 at 11:24 • can be shortened further: s=s.upcase.tr('^A-Z0-9','');s==s.reverse – Cristian Lupascu Apr 9 '13 at 12:12 # C++, 107 (miscounted), 100 (miscounted), 81 string s;for(int c:t)if(isalnum(c))s+=c|32;return s==string(s.rbegin(),s.rend()); • Exploits ASCII bit patterns. • Relies on an evil using namespace std;. • Uses bitwise AND and OR instead of the logical operators. • Uses int because it's shorter than char or auto. #include <string> using namespace std; bool IsPalindrome(const string & t) { string s;for(int c:t)if(isalnum(c))s+=c|32;return s==string(s.rbegin(),s.rend()); } #include <cassert> int main() { assert(!IsPalindrome("gorilla")); // simple failure assert( IsPalindrome("racecar")); // simple success assert( IsPalindrome("Hannah")); // case blind assert(!IsPalindrome("1999")); // digit failure assert( IsPalindrome("2002")); // digit success // Ignore spacing, punctuation, and case: assert( IsPalindrome(" \t09AZ/:@[{za90")); // boundaries assert( IsPalindrome("A man, a plan, a canal: Panama.")); assert( IsPalindrome("Eva, can I stab bats in a cave?")); assert( IsPalindrome("")); // empty string return 0; } # Lua, 56 a=io.read"*l":lower():gsub("%W","")print(a:reverse()==a) • If %W is anything like \W in regex, it also excludes characters like underscore. This is unwanted. – John Dvorak Apr 8 '13 at 19:35 • i checked, %w doesn't include _ (%W obviously includes it, then) – mniip Apr 8 '13 at 19:48 • Only function body is needed. s=s:lower():gsub('%W','')return s:reverse()==s 46 chars – Egor Skriptunoff Apr 9 '13 at 0:16 • but what about function(s) – mniip Apr 9 '13 at 4:40 Python 3/2 59 chars: def pld(i): p=[c for c in i.lower() if c.isalnum()] return(p == p[::-1]) # Haskell, 43 Using the standard libraries Control.Monad, Control.Monad.Instances, and Data.Char: ap(==)reverse.map toLower.filter isAlphaNum • I can't make this to work in ghci. import Data.Char import Control.Monad ap(==)reverse.map toLower.filter isAlphaNum neither does it with adding spaces or such, sorry I'm not too keen with Haskell :) – SlimJim Apr 12 '13 at 7:48 • @SlimJim: Oops, you need Control.Monad.Instances as well. (I’m using the Reader monad instance with ap, but that instance isn’t exported by Control.Monad.) – Jon Purdy Apr 12 '13 at 19:11 PHP 60 characters. First try on codegolf. //thank you manatwork echo($x=preg_replace('/\W/','',strtolower($c)))==strrev($x);

Example:

$c='Eva, can I stab bats in a cave?'; echo($x=preg_replace('/\W/','',strtolower($c)))==strrev($x);
//prints 1
• The parenthesis around the ternary operator's first operand are not needed. Actually neither the ternary operator is needed – just output true or false in your language's representation. And by avoiding the separate statement for the assignment to $x 1 more character can be shortened: echo($x=preg_replace('/\W/','',strtolower($c)))==strrev($x);. – manatwork Nov 27 '13 at 12:44

Python 2 64 Charecters:

i =''.join(re.findall('[a-z0-9]+',i.lower()))
return i==i[::-1]
• @manatwork If you replace all the identifiers with one character identifiers you obtain a 77 characters version. No idea why abhiram posted the ungolfed version though. – Bakuriu Apr 9 '13 at 7:04
• @Bakuriu, never mind, I missed one statement in the question: “Only method bodies are needed”. Though lines 2 and 3 gives me only 73 characters. Regarding further length reduction, no need for raw string and the capture group, making the re.findall('[a-z0-9]+',input.lower()) part 3 characters shorter. – manatwork Apr 9 '13 at 7:16
• @manatwork, I edited the post and changed the variables a little. That brought it down to 66. Yes, the raw string attribute is of no use here. – abhiram Apr 9 '13 at 8:39
• Ok, but why you insist on the capturing group in the regular expression? Works correctly without: pastebin.com/JzpNRRZU – manatwork Apr 9 '13 at 8:45
• I think it caught on with me after my recent python project involving re's :) Thanks for pointing it out. – abhiram Apr 9 '13 at 10:18

(\x->x==reverse x).map toLower.filter isAlphaNum

used like this:

(\x->x==reverse x).map toLower.filter isAlphaNum$"Eva, can I stab bats in a cave?" Smalltalk, Squeak/Pharo flavour 116 chars using traditional formatting with tabs You add two methods to String: selffles ^self = self reverse isPalindrome ^(self asUppercase asDecomposedUnicode select: #isAlphaNumeric) selffles We could of course eliminate some spaces, or use shorter method names, but let's not betray the spirit of Smalltalk. More over, this will handle French palindromes, like in http://fr.wikipedia.org/wiki/Liste_de_palindromes_fran%C3%A7ais, not many answers in this page can. ['Léon a trop par rapport à Noël' isPalindrome] assert. • Clever and useful answer! – Andrew Gray Apr 17 '13 at 18:31 # Python 3 (51 char) ### and may be Python 2 based on abhiram solution (with more agressive golfing) from re import findall def palindrome(i): i=findall('[a-z\d]',i.lower()) return i==i[::-1] print(palindrome(input('Phrase: '))) may be shortened to 46 chars, using RE '\w' and variant with extremely shortened function body (27 chars) import re l=str.lower f=re.compile('[a-z\d]').findall def palindrome(i):i=f(l(i));return i==i[::-1] print(palindrome(input('Phrase: '))) ## Windows PowerShell, 5647 45 chars Updated (see comments), and can remove the brackets around the regex: ($s=$s-replace'\W')-eq(-join$s[$s.length..0]) Original (56)$s=$s-replace'[^\w]','';$s-eq($s[-1..-$s.length]-join'')

Original Un-golfed:

$s = "Eva, can I stab bats in a cave?"$s = $s -replace '[^\w]', ''$rev = $s[-1..-$s.length] -join ''
$s -eq$rev
• You can golf this down to 47 chars like this: ($s=$s-replace'[\W]')-eq(-join$s[$s.length..0]) – SpellingD Nov 26 '13 at 22:47
• @SpellingD: Nice! I'm new at code golfing, thanks for the improvement – goric Nov 27 '13 at 12:59
• you can remove the right parenthesis also: ($s=$s-replace'\W')-eq-join$s[$s.length..0]. – mazzy Dec 10 '18 at 13:47

# C++, 74 bytes

This code is actually really elegant, and easy to understand (when formatted correctly). I don't believe it's possible to get any shorter in C++, and it doesn't use any standard library functions.

p(auto c){auto e=c;while(*e)++e;--e;while(*e==*c&e>c)--e,++c;return e<=c;}

Example usage:

p("Hello"); //Outputs 0
p(""); //Outputs 1
p("a"); //Outputs 1
p("HellolleH"); //Outputs 1

Nicely formatted version:

p(auto c)
{
auto e=c;
while(*e) ++e;
--e;
while(*e==*c & e>c)--e,++c;
return e<=c;
}
• error: ISO C++ forbids declaration of ‘p’ with no type your function should have a return type. – Karl Napf Nov 23 '16 at 17:09
• I bet this does not ignore case, whitespace and control characters. – Titus Apr 4 '17 at 23:53
• You can save a character with while(*++e); instead of while(*e)++e;. But as Titus mentioned this answer is invalid. – Nick Matteo Apr 25 '17 at 17:04

# PHP, 26 84 80 78 62 63 bytes

<?=strrev($s=strtolower(preg_replace("#\W#","",$argv[1])))==$s; takes input from first command line argument; prints 1 for truthy, empty string for falsy. I18n is a littly expansive, as there is no multibyte alternative for strrev (110 bytes; run with -r): preg_match_all("#.#us",$s=strtolower(preg_replace("#\W#u","",$argv[1])),$m);echo$s==join(array_reverse($m[0]);

utf8_strrev blatantly stolen from the PHP manual. You might also want to take a look at this blog post.

• Come on Titus... This fails the spec. – Christoph Apr 4 '17 at 8:04
• @Christoph Yeah I sometimes should fully read that. Fixed. – Titus Apr 4 '17 at 12:54
• Hm -R would cause problems with line breaks in the string to test wouldn't it? From the spec " -R <code> Run PHP <code> for every input line". Moreover <?=strrev($s=strtolower(preg_replace("#\W#","",$argn)))==$s;would be shorter. – Christoph Apr 4 '17 at 13:42 • @Christoph Nice idea, but there is no$argn without -R. – Titus Apr 4 '17 at 14:06
• $argv[1]="O Genie, der Herr ehre dein Ego!"; # :D – Titus Apr 5 '17 at 0:24 ## Ruby, 48 p((g=gets.upcase.gsub /[^A-Z\d]/,'')==g.reverse) Quite simple, and hastily made so not golfed too much. I shall golf it more later. # Pylongolf2, 24 bytes c╨2"[^a-zA-Z]"-_╨1=~ c takes the input, ╨2 to convert to lower case. I then push a regex onto the stack and use - to remove all non-alphabetical characters in the input. _ duplicates the input. ╨1 reverses it and = then compares them. ~ prints the stack in the end which prints either true or false. • Does this ignore the punctuation, whitespace and control characters? – MickyT Mar 31 '16 at 19:05 • My bad, this version does not. I will fix it. – user47018 Mar 31 '16 at 20:06 • Fixed the problem. – user47018 Mar 31 '16 at 20:08 # PowerShell, 194 190 bytes A recursive implementation to show how an unnamed PowerShell scriptblock can call itself.$P={param([string]$s)$s=($s-replace'[^a-z]').tolower();if(!$s){return $true};if($s.length-lt4){return $s[0]-eq$s[-1]};$s[0]-eq$s[-1]-and(&$MyInvocation.MyCommand.ScriptBlock$s.trim($s[0]))} ungolfed:$P={
param([string]$s)$s=($s-replace'[^a-z]').tolower(); if(!$s){return $true}; if($s.length-lt4){return $s[0]-eq$s[-1]};
$s[0]-eq$s[-1]-and(&$MyInvocation.MyCommand.ScriptBlock$s.trim($s[0])) } tests: &$P "Eva, can I stab bats in a cave?"
&$P "Eva, can I stab cats in a cave?" &$P "A man, a plan, a canal. Panama!"
&$P "A man, a plan, a big shovel, a canal. Panama!" &$P "Madam, I'm Adam."
&$P "Madam, I'm Adam Corolla." &$P "757"
&\$P "Boeing 757"
• Shouldn´t that be [^a-z0-9]? – Titus Apr 4 '17 at 23:56

# 05AB1E, 4 bytes (non-competing)

Non-competing, since the language postdates the challenge. Code:

álÂQ

Explanation:

á     # Only keep the alphabetic characters.
l    # Lowercase the characters.
Â   # Bifurcate, which duplicates the letters and reverses the duplicate.
Q  # Check if they are equal.

Uses the CP-1252 encoding. Try it online!.

• Tried to run it via your link. Program output is "1" – Christopher Perry Apr 5 '17 at 4:57

# Jelly, 10 Characters (Non-competing)

fØBŒl
UÇ⁼Ç

Returns 1 if true, 0 if false

Try it Online!

• Does it ignore case, whitespace and control characters? A breakdown would be nice. – Titus Apr 4 '17 at 23:55
• The current state of Jelly allows for solving this in 7 bytes: fØBŒlŒḂ: f filter to keep ØB the set [a-zA-Z0-9] and Œl convert to lowercase, then ŒḂ test if palindrome. – steenbergh Apr 5 '17 at 8:11