25
\$\begingroup\$

Your challenge is to find the file extension of a provided filename:

hi.txt -> txt or .txt
carrot.meme -> meme or .meme
lol (undefined behavior)
what..is..this..file -> file or .file
.bashrc -> bashrc or .bashrc
[email protected][]h -> h0wC[]h or .h0wC[]h
agent.000 -> 000 or .000

You must get the text from the last . or after the last . to the end of the string. The first capturing group match of the regular expression /\.([^.]+)$/ works, and so does splitting the input on .s and returning the last one.

The file name will always contain at least one ., but it may contain multiple .. (see examples)

The input will always match ^[.a-zA-Z0-9^!\[\]{}@$%+=]+$.

\$\endgroup\$
7
  • 20
    \$\begingroup\$ Please consider using the Sandbox in the future to get feedback on your challenges before posting them to the main site. \$\endgroup\$
    – user45941
    May 16, 2017 at 20:45
  • 1
    \$\begingroup\$ codegolf.meta.stackexchange.com/a/12432/59376 - Got this idea from your challenge. \$\endgroup\$ May 16, 2017 at 21:51
  • \$\begingroup\$ @carusocomputing nice challenge! \$\endgroup\$
    – user58826
    May 17, 2017 at 0:06
  • 2
    \$\begingroup\$ why the negative votes? Is this challenge "exceedingly trivial" or so ? \$\endgroup\$
    – Abel Tom
    May 17, 2017 at 5:09
  • \$\begingroup\$ @AbelTom edit history would suggest downvotes were for the lack of specifications in the first draft of this question. \$\endgroup\$ May 17, 2017 at 5:12

104 Answers 104

16
\$\begingroup\$

Retina, 5 bytes

.*\.

Replaces everything and a dot with nothing at all.

Try it online!

\$\endgroup\$
0
11
\$\begingroup\$

JavaScript (ES6), 19 bytes

Returns the full filename when there's no file extension. I suppose this is an acceptable undefined behavior.

let f =

s=>s.split`.`.pop()

console.log(f("hi.txt"))               // -> txt
console.log(f("carrot.meme"))          // -> meme
console.log(f("lol"))                  // -> undefined behavior
console.log(f("what..is..this..file")) // -> file
console.log(f("[email protected][]h")) // -> h0wC[]h
console.log(f(".bashrc")) // -> bashrc

\$\endgroup\$
1
  • \$\begingroup\$ The point of undefined behavior is that anything goes. Although, nasal demons, while still undefined behavior, might fail the "no malicious programs" clause. \$\endgroup\$ May 27, 2017 at 11:26
10
\$\begingroup\$

Mathematica, 13 22 bytes

Edit: Not sure how I missed the ".bashrc" test case. Thanks to Artyer for keeping me honest.

FileExtension["a"<>#]&

If the input matches \.[^.]+, then FileExtension just returns the empty string, so we prepend the letter a. In any other case, prepending a doesn't affect output of FileExtension.

\$\endgroup\$
7
  • 11
    \$\begingroup\$ A Mathematica builtin...no surprise. \$\endgroup\$
    – user58826
    May 16, 2017 at 21:03
  • 1
    \$\begingroup\$ I'd be surprised if there weren't any mathematica builtins for any question possible \$\endgroup\$
    – sagiksp
    May 17, 2017 at 5:52
  • \$\begingroup\$ I don't have access to Mathematica, but I would suspect that .ext would result in nothing, which failes for .bashrc needing to output bashrc (It fails in Mathics) \$\endgroup\$
    – Artyer
    May 17, 2017 at 11:22
  • \$\begingroup\$ Apparently it works \$\endgroup\$
    – user58826
    May 17, 2017 at 11:36
  • \$\begingroup\$ Mathematica just needs to meta built-ins Create Built-in XXXXXXXX. \$\endgroup\$ May 17, 2017 at 13:02
10
\$\begingroup\$

POSIX Shell, 13

echo ${1##*.}

Try it online.

\$\endgroup\$
8
\$\begingroup\$

c function, 21

  • 1 byte saved thanks to @Dennis.
  • 3 bytes saved thanks to @JohanduToit.
  • 2 bytes saved thanks to @Neil.
  • 1 byte saved thanks to @algmyr.
f(s){s=rindex(s,46);}

Try it online.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ If you're ok with using legacy POSIX functions you could use rindex to save a byte. \$\endgroup\$
    – algmyr
    May 17, 2017 at 19:15
  • \$\begingroup\$ @algmyr Sure, it works fine on TIO, so I'll use it. I'd never heard of rindex() before - thanks for the tip! \$\endgroup\$ May 17, 2017 at 19:34
6
\$\begingroup\$

Japt, 3 bytes

2 bytes of code, +1 for the h flag.

q.

Explanation:

q.       Split the input by `.`
   -h    Return the last item

Try it online!

\$\endgroup\$
6
\$\begingroup\$

05AB1E, 4 bytes

'.¡¤

Try it online! or Try All Tests

'.   # Push '.'
  ¡  # Split on occurrences of '.'
   ¤ # Tail
\$\endgroup\$
1
  • \$\begingroup\$ What? I've never seen a split occurences in the wiki. Edit: Now I found it! \$\endgroup\$
    – mekb
    Jul 18, 2019 at 11:09
4
\$\begingroup\$

Neo4j Cypher, 24 bytes

return split($i,".")[-1]

Input is in a param (i), probably the only way for cypher to take input. Pretty straightforward. Cypher has never been used on PPCG before

\$\endgroup\$
4
\$\begingroup\$

PHP, 21 Bytes

<?=pathinfo($argn,4);

Try it online!

is a shorter expression for

<?=pathinfo($argn)[extension];

pathinfo

PHP, 27 Bytes

<?=end(explode(".",$argn));

explode

Try it online!

PHP <7.0, 26 Bytes

<?=end(split("\.",$argn));

deprecated split

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Are you counting a trailing newline for the first one? It should be 27 bytes, not 28. \$\endgroup\$ May 16, 2017 at 21:45
  • \$\begingroup\$ @ConorO'Brien Thank You .I have count after copy and paste from the split version a `` \$\endgroup\$ May 16, 2017 at 21:49
  • 2
    \$\begingroup\$ The pathinfo() based one could be <?=pathinfo($argn,4);. \$\endgroup\$
    – manatwork
    May 17, 2017 at 11:56
4
\$\begingroup\$

Taxi, 1397 bytes

Go to Post Office:w 1 l 1 r 1 l.Pickup a passenger going to Chop Suey.Go to Chop Suey:n 1 r 1 l 4 r 1 l.[a]Pickup a passenger going to Narrow Path Park.Go to Narrow Path Park:n 1 l 1 r 1 l.Go to Chop Suey:e 1 r 1 l 1 r.Switch to plan "b" if no one is waiting.Switch to plan "a".[b]Go to The Babelfishery:n 1 l 1 l.[c]Go to Fueler Up:n.Go to Joyless Park:n 2 r.Go to Narrow Path Park:w 1 r 3 l.Pickup a passenger going to Cyclone.Go to Cyclone:w 1 l 1 r 2 l.Pickup a passenger going to Crime Lab.Pickup a passenger going to Joyless Park.'.' is waiting at Writer's Depot.Go to Writer's Depot:s.Pickup a passenger going to Crime Lab.Go to Crime Lab:n 1 r 2 r 2 l.Switch to plan "c" if no one is waiting.Go to Narrow Path Park:n 5 l.[d]Pickup a passenger going to Chop Suey.Go to Chop Suey:e 1 r 1 l 1 r.Go to Narrow Path Park:n 1 l 1 r 1 l.Switch to plan "e" if no one is waiting.Switch to plan "d".[e]Go to Joyless Park:e 1 r 3 l.Switch to plan "f" if no one is waiting.Pickup a passenger going to Narrow Path Park.Go to Fueler Up:w 1 l.Go to Narrow Path Park:n 4 l.Switch to plan "e".[f]Go to Narrow Path Park:w 1 r 3 l.[g]Switch to plan "h" if no one is waiting.Pickup a passenger going to KonKat's.Go to KonKat's:e 1 r.Pickup a passenger going to KonKat's.Go to Narrow Path Park:n 2 l.Switch to plan "g".[h]Go to KonKat's:e 1 r.Pickup a passenger going to Post Office.Go to Post Office:s 3 r 1 l.

Try it online!

Taxi doesn't have a reverse function so this ballooned pretty quickly. The logic is:

  1. Break the string into characters
  2. Reverse the array
  3. Iterate through each until a period is found, storing each in a FIFO array
  4. Empty the array (because there's only one LIFO array available)
  5. Dump the FIFO array into the LIFO array
  6. Concatenate the LIFO array and output
\$\endgroup\$
3
\$\begingroup\$

GNU Make, 12 bytes

$(suffix $1)

Not using a builtin, 27 bytes:

$(lastword $(subst ., ,$1))
\$\endgroup\$
3
\$\begingroup\$

Batch, 10 bytes

@echo %~x1

Strangely competitive for once.

\$\endgroup\$
3
\$\begingroup\$

V, 5, 3 bytes

Since more of this answer is unprintable than printable, here is a hexdump:

00000000: cd81 ae                                  ...

Try it online!

This uses Jan Dvorak's algorithm, it just happens to be a more efficient encoding of it.

Explanation:

Í       " Remove all occurrences of:
 0x81   "   Anything (greedy)
     ®  "   Followed by a dot 

Old solution:

$T.d|
\$\endgroup\$
3
  • \$\begingroup\$ Explanation please? \$\endgroup\$ May 17, 2017 at 13:18
  • \$\begingroup\$ @EriktheOutgolfer Done \$\endgroup\$
    – DJMcMayhem
    May 17, 2017 at 16:39
  • \$\begingroup\$ Wait ® means followed by a dot? Lol that's weird. \$\endgroup\$ May 17, 2017 at 16:42
3
\$\begingroup\$

C# (Visual C# Interactive Compiler), 22 bytes

s=>s.Split('.').Last()

Implicit using System.Linq; FTW!

Try it online!

\$\endgroup\$
3
\$\begingroup\$

FORTRAN 90, 87 bytes

CHARACTER(99)F,L
READ*,F;DO I=1,LEN(F)
IF(F(I:I)=='.')L=F(I:LEN(F))
ENDDO
PRINT*,L
END

A shorter version in FORTRAN 90.


FORTRAN 77, 137 bytes

      PROGRAMC;IMPLICITCHARACTER*99(F)
      READ*,F;DOI=LEN(F),1,-1;IF(F(I:I).EQ.'.')THEN
      PRINT*,F(I:LEN(F));EXIT;ENDIF;ENDDO;END

There is no space in PROGRAM C, nor in IMPLICIT CHARACTER. It works (!) in gfortran, but I'm not sure it works in others compilers. The program takes input from stdin and outputs the extension with the period. The total length of the file name is limited by 99.

\$\endgroup\$
3
\$\begingroup\$

Vim, 5 bytes

$F.d0

Explanation: find last . in line, delete everything before it

Another, longer, but in my opinion still interesting approach with 9 bytes (notice the trailing new line)

d/.*\./e

This one works similarly, 5 bytes (again, trailing new line):

d?\.

\$\endgroup\$
3
\$\begingroup\$

PowerShell, 34 26 bytes

-8 bytes thanks to @mazzy

(Read-Host).Split('.')[-1]

Takes input from STDIN. Actually managed to golf it down shorter than the built-in.

PowerShell, 20 bytes

($args-split'.')[-1]

Takes input from commandline arguments. Big thanks to @mazzy again!

PowerShell (with built-in), 36 bytes

[IO.Path]::GetExtension((Read-Host))
\$\endgroup\$
1
  • 1
    \$\begingroup\$ you can save some bytes. try this ($args-split'.')[-1] see About Automatic Variables \$\endgroup\$
    – mazzy
    Oct 26, 2018 at 16:38
3
\$\begingroup\$

Forth (gforth), 45 bytes

: f begin 1 -1 d+ s" ."search 0= until type ;

Try it online!

Code Explanation

: f              \ start a new word definition
  begin          \ start an indefinite loop
    1 -1 d+      \ remove the first character from the string
    s" ."search  \ find the length and starting address of the first substring that starts with '.'
    0=           \ check if '.' was found in the string
  until          \ end the loop if not
  type           \ output the result
;                \ end the word definition
 
\$\endgroup\$
3
\$\begingroup\$

Python 3, 29 bytes

print(input().split(".")[-1])
\$\endgroup\$
3
\$\begingroup\$

Rust, 34 bytes

|p|p.extension().or(p.file_stem())

Usable as a fn(&std::path::Path) -> Option<&std::ffi::OsStr>.

Try it online!

\$\endgroup\$
2
\$\begingroup\$

sed, 8 bytes

s:.*\.::

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Jelly, 4 bytes

ṣ”.Ṫ

A monadic link taking the file name and returning the extension with no leading ..

Try it online!

How?

Literally does what was asked...

ṣ”.Ṫ - Main link: list of characters, f
 ”.  - literal '.'
ṣ    - split f at occurrences of '.'
   Ṫ - tail (get the last chunk)
\$\endgroup\$
2
\$\begingroup\$

Go, 85 bytes

Go is... troublesome.

import(."fmt"
."os"
."strings")
func main(){s:=Split(Args[1],".");Print(s[len(s)-1])}

Try it online!

A sample of parentheses from the code:

()(){([])([()])}
\$\endgroup\$
3
  • 3
    \$\begingroup\$ ()(){([])([()])} — is it a valid Brain-Flak? \$\endgroup\$
    – eush77
    May 16, 2017 at 21:08
  • 6
    \$\begingroup\$ @eush77 It's technically valid Brain-Flak, since it will run without errors, but it doesn't do anything interesting/useful. It's either just the literal 2 with no instructions/commands or anything or an infinite loop that continuously allocates more memory, depending on input. \$\endgroup\$
    – DJMcMayhem
    May 16, 2017 at 21:27
  • \$\begingroup\$ Using filepath.Ext will save you a few bites \$\endgroup\$
    – powelles
    May 16, 2017 at 22:17
2
\$\begingroup\$

JavaScript (ES6), 33 31 28 bytes

s=>s.slice(s.lastIndexOf`.`)

Spec change in comments removes the need for +1.

-3 bytes thanks to nderscore

\$\endgroup\$
1
  • 1
    \$\begingroup\$ -3 with slice and template string execution: s=>s.slice(s.lastIndexOf`.`) \$\endgroup\$
    – nderscore
    May 16, 2017 at 21:42
2
\$\begingroup\$

Common Lisp, 57 bytes

(lambda(s)(#1=reverse(subseq #2=(#1# s)0(search"."#2#))))

Try it online (added some bytes to call this anonymous function and display returned string)

Explanation

(#1=reverse ...)     ;reverse is now accessible with #1# - saves 1 byte. I 
                     ;also need to reverse output of function inside to 
                     ;get extension in correct order
#2=(#1# s)           ;reverse of input string is now accessible with #2#
(search"."#2#)       ;I take reversed string and search for "." to get position of 
                     ;first instance of "." in string from the end of it
(subseq ... 0 ...)   ;get part of reversed string, 
                     ;starting from first character and ending just 
                     ;before first occurance of "."
                     ;this gives reversed extension

I get substring of reversed string, starting from 0, ending on this

\$\endgroup\$
2
\$\begingroup\$

Gema, 3 characters

*.=

Sample run:

bash-4.4$ gema '*.=' <<< 'what..is..this..file'
file
\$\endgroup\$
2
\$\begingroup\$

Javascript (ES5), 38 bytes

function(s){return s.split(".").pop()}
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Just so you know, the downvote was cast automatically by the Community user when your answer was edited. I consider this a bug. \$\endgroup\$
    – Dennis
    May 16, 2017 at 22:57
  • \$\begingroup\$ plz fix that if you can! \$\endgroup\$
    – Sinned
    May 17, 2017 at 0:56
2
\$\begingroup\$

C#, 33 41 bytes

a=>a.Split('.').Last();

Edit as suggested:

using System.Linq;a=>a.Split('.').Last();
\$\endgroup\$
4
  • 1
    \$\begingroup\$ You need to include using Sytem.Linq; into your byte count \$\endgroup\$ May 17, 2017 at 12:17
  • \$\begingroup\$ And also a=>a.Split('.').Last(); implicit return is shorter \$\endgroup\$ May 17, 2017 at 12:18
  • \$\begingroup\$ @TheLethalCoder Thanks for suggested fixes, still new to this :) \$\endgroup\$
    – LiefdeWen
    May 17, 2017 at 12:23
  • \$\begingroup\$ I'm surprised this is longer than my solution using Path... \$\endgroup\$ May 17, 2017 at 13:03
2
\$\begingroup\$

Awk, 14 13 characters

(10 9 characters code + 4 characters command line option.)

{$0=$NF}1

Thanks to:

  • Robert Benson for spotting the unnecessary semicolon (-1 character)

Sample run:

bash-4.4$ awk -F. '{$0=$NF}1' <<< $'hi.txt\ncarrot.meme\nlol\nwhat..is..this..file\n.bashrc\[email protected][]h'
txt
meme
lol
file
bashrc
h0wC[]h
\$\endgroup\$
3
  • \$\begingroup\$ You don't need the ;. and just FYI, awk '{$0=$NF}1 works, no command line option needed. Oh... I must be tired. I see what you did there. You do need the command line option. \$\endgroup\$ May 17, 2017 at 18:18
  • 1
    \$\begingroup\$ Thank you, @RobertBenson. I have no idea why I put that ; there. \$\endgroup\$
    – manatwork
    May 17, 2017 at 18:53
  • \$\begingroup\$ If there is always a character after the last ., then $0=$NF is enough, with -F. command line option. \$\endgroup\$ Jun 10, 2021 at 23:50
2
\$\begingroup\$

Lua, 53 30 bytes

Replaces everything upto the last . with the empty string ''.

Double parenthesis to select only the first return value of gsub.

Any golfing tips are welcome, I'm rusty in lua...

print(((...):gsub('.*%.','')))

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.