g | x | w | all
Bytes Lang Time Link
165C64 Basic250803T181810ZOSI8
02305AB1E250814T080727ZKevin Cr
132Python250803T231053ZLucenapo
112C clang250805T134541Zjdt
053Pyth250804T220202ZSynoli
103Perl 5 pl250801T231611Zgood old
118JavaScript ES6250801T102802ZArnauld
047Charcoal250803T125737ZNeil
083Retina250802T194431ZNeil
233Python3250801T153528ZAjax1234
214JavaScript Node.js250801T084636Zrydwolf
014Nekomata250801T034829Zalephalp

C64 Basic, 210 165 bytes

Here's a much shorter version of the original program. A big thanks to Robin from 8-Bit Show And Tell, who took a close look at my original code and was able to shorten it considerably.

0inputa$:j=1
1l=len(a$):i=j:j=l
2s=j-i:fOx=0tos:ifl<3ori=l-1tH?a$:eN
3s=s+(mI(a$,x+i,1)=mI(a$,j-x,1)):nE:ifs<0tHa$=leF(a$,i-1)+mI(a$,j+1):j=2
4j=j-1:on1-(j-1>i)gO1,2

C64 screenshot

Try in emulator

05AB1E, 23 bytes

¸ΔεDŒāÌù˜ʒÂQ}õªδK}˜ê}éн

Try it online or verify all test cases.

Explanation:

¸              # Wrap the (implicit) input-string into a singleton list
 Δ             # Loop until the result no longer changes:
  ε            #  Map over each inner string:
   D           #   Duplicate the current string
    Œ          #   Pop the copy, and get all its substrings
     āÌù˜      #   Remove all substrings of lengths 1 and 2:
     ā         #    Push a list in the range [1,length] (without popping the list)
      Ì        #    Increase each value by 2: [3,length+2]
       ù       #    Map each value to the substrings of just that length
        ˜      #    Flatten this list of lists
         ʒ     #   Filter the remaining strings:
          ÂQ   #    Check that the string is a palindrome:
          Â    #     Bifurcate the string; short for Duplicate & Reverse copy
           Q   #     Check that the two strings are the same
         }õª   #   After the filter: append an empty string in case none are left
            δ  #   Map over each of the valid palindromes:
             K #    Remove them from the duplicated current string
  }˜           #  After the inner map: flatten the list of lists
    ê          #  (Sort and) uniquify this list of strings
 }é            # After the changes-loop: sort the resulting strings by length
   н           # Pop and keep the first/shortest one
               # (which is output implicitly as result)

Python, 146 145 140 132 bytes

def f(s):L,*w=len(s),s;[s[a:b]==s[a:b][::-1]==(w:=w+[f(s[:a]+s[b:])])for a in range(L)for b in range(a+3,L+1)];return min(w,key=len)

Attempt This Online!

C (clang), 212 199 148 140 133 121 118 112 bytes

i,j,m,n;f(*s){for(i=0;s[i];i++)for(j=wcslen(s);--j>i+1;)for(m=i,n=j;m>n?wcscpy(s+i,s-~j)<f(s):s[m++]==s[n--];);}

Try it online!

-14 bytes thanks to @ceilingcat!

Pyth, 53 bytes

L&>lb2qb_bL{u+G|{m|s-Fdkm,dy#df.EyMT./H]HbYh.mlbu'G]w

Try it online!

Explanation

Is b an eligible palindrome?

L                   # Declare a lambda `g(b)` …
 &                  # … which tests if both of the following are true:
  >lb2              #   b is more than 2 characters long?
      qb_b          #   b is equal to the reversed form of itself?

Remove a single palindrome

This lambda tries to find all the ways to remove a single palindrome. We accept a list of strings. For each string, we try to remove a single palindrome. If we can’t find any palindromes, then that means the string can’t be made smaller and is a potential winning candidate, so we keep it in the list. If we have a palindrome, then we remove it and keep the result. If we find more than one palindrome, we don’t know yet which one is best, so we remove each palindrome separately and keep all the results.

                                Y # We’re going to use reduce, so start with an empty list.
                               b  # Our input, the list of strings. Let’s feed it into reduce.
                              H   # Maybe the string contains no palindromes. If so, keep it around …
                             ]    # … but for interface parity, let’s wrap it in a singleton list.
                            H     # With that out of the way, take the characters from our string …
                          ./      # and explode it into a massive list of all possible substring partitions.
                       yMT        # For each substring, check whether it is a valid palindrome …
                     .E           # … and if that happens at least once in our partition, then …
                    f             # … keep the partition around, otherwise throw it away.
                 y#d              # In our right hand, we take the substrings that are palindromes …
              m,d                 # … in our left hand, we take the partition itself …
          -Fd                     # … and fold them into each other, eliminating the palindrome.
                                  # Conveniently, folding has removed each palindrome separately,
                                  # and multiple palindromes have automatically split into two separate
                                  # intermediate results. This is good, because we don’t know yet
                                  # which palindrome was the best one to remove, so let’s keep all the options.
       m s                        # Each result is still in form of a partition, so mend it back into a string.
        |    k                    # Is our partition empty? If so, fix the mess that `s` has made with its default value 0.
      {                           # Our power-set shenanigans are causing abysmal performance, so let’s
                                  # deduplicate what we have to counteract the effect at least a little.
     |                            # If there were no palindromes at all, fall back to the singleton list we prepared earlier.
  u+G                             # Repeat for each input string and collect results.
 {                                # Deduplicate the resulting list once again …
L                                 # … and define a lambda named `'` so we can repeat all of the above over and over.

Main routine

         w          # Start with the input string …
        ]           # … and wrap it inside a singleton list. That’s our initial state.
      'G            # From each list element, try removing a single palindrome …
                    # … while keeping track of intermediate solutions …
     u              # … over and over again, until our list no longer changes.
                    # The list elements are now our potential winning candidates.
   lb               # Look at the number of characters …
 .m                 # … of each candidate. Those with minimal length are our solutions.
h                   # More than one solution? If so, pick the first one.

Perl 5 -pl, 103 bytes

@,=$s=$_;/((.)(?1)\2|(.)(.)\4?\3)?(??{$1?push@,,$`.$':length$s>y!!!c?$s=$_:1;0})/,$_=pop@,while@,;$_=$s

Try it online!

More readable:

@, = $s = $_;
/
    ( (.)(?1)\2 | (.)(.)\4?\3 )?
    (??{ 
        $1 ? push @,, $` . $'
           : length $s > y!!!c ? $s = $_ : 1;
        0
    })
/x,
$_ = pop @, while @,;
$_ = $s

Perl 5, (non-competing) 458 bytes

$s = $_;
%seen = ();
while () {
    /
        (?>^.*?)
        ( 
            (
                (.)(?-3)\g-1|(.)(.)\g-1?\g-2 
            )
            (?{ 
                $x = substr( $_, 0, $-[2] ) . substr( $_ , $+[2] );
                unless ( $seen{ $x } ++ ) {
                    push @a, $x;
                    $s = $x if length( $s ) > length( $x )
                }
            })
        )
    /x;
    last unless @a;
    $_ = pop @a
}
$_ = $s;

Try it online!

Short version is terribly inefficient. Just for fun, this is a much faster version (approx. 1 sec for 16 "go"'s in linked TIO's input vs. 9 in the challenge's test case), which hopefully generates correct results.

JavaScript (ES6), 118 bytes

I/O format: arrays of characters.

f=(s,_=o=s)=>s.map((n,i)=>s.map(_=>(q=[...s],p=q.splice(i,n=-~n))[2]&&p+""==p.reverse()&&f(q,0)),s[o.length]?0:o=s)&&o

Try it online!

Commented

f = (               // f is a recursive function taking:
  s,                //   s[] = input
  _ = o = s         //   o[] = output, initialized to the input
) =>                //
s.map((n, i) =>     // for each character at index i in s[],
                    // with n zero'ish:
  s.map(_ =>        //   for each character in s[]:
    (               //
      q = [...s],   //     q[] = copy of s[]
      p = q.splice( //     p[] = palindrome candidate
        i,          //       extracted from q[] at index i
        n = -~n     //       with a length of (at most) n
      )             //       where n is incremented
    )[2] &&         //     if p[] is at least 3 characters long
    p + "" ==       //     and is a palindrome, i.e. it's equal
    p.reverse() &&  //     to its reversed form:
      f(q, 0)       //       do a recursive call with q[]
                    //       (the 2nd argument is here only
                    //       to leave o[] unchanged)
  ),                //   end of inner map()
  s[o.length] ?     //   if s[] is longer than o[]:
    0               //     do nothing
  :                 //   else:
    o = s           //     update o[] to s[]
) && o              // end of outer map(); return o[]

Charcoal, 47 bytes

⊞υSFυFLιFEι✂ικμF∧›Lλ²⁼λ⮌λ⊞υΦι÷⁻ξκLλ§υ⌕EυLι⌊EυLι

Try it online! Link is to verbose version of code. Explanation:

⊞υSFυ

Start searching for palindromic substrings starting with the input.

FLιFEι✂ικμF∧›Lλ²⁼λ⮌λ

If this substring is long enough and palindromic, then...

⊞υΦι÷⁻ξκLλ

... filter it out from the string and push the result to the list of strings to test.

§υ⌕EυLι⌊EυLι

Output the shortest resulting string.

Retina, 83 bytes

+%/(.)+(.)\2?(?<-1>\1)+(?(1)^)/&L$w`(.)+(.)\2?(?<-1>\1)+(?(1)^)
$`$'
O#$`
$.&
L`^.*

Try it online! Link includes faster¹ test cases. Explanation:

+%/(.)+(.)\2?(?<-1>\1)+(?(1)^)/&`

Repeat on those lines that contain a palindrome...

L$w`(.)+(.)\2?(?<-1>\1)+(?(1)^)

... for all overlapping matches...

$`$'

... remove the match to give the resulting line.

O#$`
$.&

Sort the lines in ascending order of length.

L`^.*

Output only the first (i.e. shortest) line.

¹gogogogogogogogogonow is too slow for the w style of overlapping match but the v style also happens to work in this case within TIO's time limit.

Python3, 233 bytes

def f(s):
 q,r,S=[s],[],[s]
 for s in q:
  if[]==(o:=[(i,j)for i in range(len(s))for j in range(i+1,len(s)+1)if s[i:j]==s[i:j][::-1]and j-i>2]):r+=[s]
  for i,j in o:
   if(U:=s[:i]+s[j:])not in S:S+=[U];q+=[U]
 return min(r,key=len)

Try it online!

JavaScript (Node.js), 214 bytes

f=s=>[...s,t=[]].map((_,i,a)=>[...Array(i).keys()].map(j=>j<i-2&&s.slice(j,(j+i)/2|0)==a.slice((j+i+1)/2|0,i).reverse().join``&&t.push(s.slice(0,j)+s.slice(i))))&&0 in t?t.map(f).sort((x,y)=>x.length-y.length)[0]:s

Try it online!

Explanation

Nekomata, 14 bytes

ʷ{;;$ƀ=tŁ¿,}aş

Attempt This Online!

Extremely slow for long inputs that contain many palindromes.

ʷ{;;$ƀ=tŁ¿,}aş
ʷ{         }      Loop until failure
  ;;                Split the input into three parts
    $ƀ=             Check that the second part is a palindrome
       tŁ           Check that the second part has length >= 3
         ¿,         If so, join the first and third parts; otherwise fail
            aş    Find the shortest possible solution

If there are multiple shortest solutions, Nekomata will print all of them. You can add the -1 flag to only print the first one.