File extension is in extensions list

From Rosetta Code
File extension is in extensions list is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Given a file name and a list of extensions (including the dot), tell whether the file's extension is in the extensions list. The check should be case insensitive. The file might not have an extension.

AWK

<lang AWK>

  1. syntax: GAWK -f FILE_EXTENSION_IS_IN_EXTENSIONS_LIST.AWK

BEGIN {

   n = split("txt,gz,bat,c,c++,exe,pdf",arr,",")
   for (i=1; i<=n; i++) {
     ext_arr[tolower(arr[i])] = ""
   }
   filenames = "c:,txt,text.txt,text.TXT,test.tar.gz,test/test2.exe,test,foo.c,foo.C,foo.C++,foo.c#,foo.zkl,document.pdf"
   n = split(filenames,fn_arr,",")
   print("      EXT   FILENAME")
   for (i=1; i<=n; i++) {
     ext = ""
     if (fn_arr[i] ~ /\./) {
       ext = tolower(fn_arr[i])
       while (match(ext,/\./) > 0) {
         ext = substr(ext,RSTART+1)
       }
     }
     ans = (ext in ext_arr) ? "true" : "false"
     printf("%-5s %-5s %s\n",ans,ext,fn_arr[i])
   }
   exit(0)

} </lang>

output:

      EXT   FILENAME
false       c:
false       txt
true  txt   text.txt
true  txt   text.TXT
true  gz    test.tar.gz
true  exe   test/test2.exe
false       test
true  c     foo.c
true  c     foo.C
true  c++   foo.C++
false c#    foo.c#
false zkl   foo.zkl
true  pdf   document.pdf

D

<lang d>void main() {

   import std.stdio, std.string, std.path, std.algorithm;
   immutable exts = [".txt", ".gz", ".bat", ".c", ".c++", ".exe", ".pdf"];
   immutable fileNames =
   "text.txt
   text.TXT
   test.tar.gz
   test/test2.exe
   test\\test2.exe
   test
   a/b/c\\d/foo
   foo.c
   foo.C
   foo.C++
   foo.c#
   foo.zkl
   document.pdf";
   foreach (fName; fileNames.split)
       writeln(fName, ": ", exts.canFind(fName.extension.toLower));

}</lang>

Output:
text.txt: true
text.TXT: true
test.tar.gz: true
test/test2.exe: true
test\test2.exe: true
test: false
a/b/c\d/foo: false
foo.c: true
foo.C: true
foo.C++: true
foo.c#: false
foo.zkl: false
document.pdf: true

Haskell

<lang Haskell> import Data.List import qualified Data.Char as Ch

toLower :: String -> String toLower = map Ch.toLower

isExt :: String -> [String] -> Bool isExt filename extensions = any (`elem` (tails . toLower $ filename)) $ map toLower extensions </lang>

The code defining isExt could be done point free: <lang Haskell> isExt filename = any (`elem` (tails . toLower $ filename)) . map toLower </lang>

Overcoming the one-liner urge on behalf of being more comprehensible would give: <lang Haskell> isExt filename extensions = any (`elem` allTails) lowerExtensions

                           where allTails = tails . toLower $ filename

lowerExtensions = map toLower extensions </lang>

J

Solution: <lang j>getExt=: }.~ i:&'.' isExt=: e.~&:(tolower&.>) getExt&.>@boxopen</lang> Usage: <lang j> Exts=: <;._1 ' .o .ijs .ij .p'

  TestFiles=: <;._1 ' foo.o blab.iJ dram. lat.P win.dll foo'
  Exts isExt TestFiles

1 1 0 1 0 0</lang>

Java

Works with: Java version 1.5+

<lang java5>import java.util.Arrays; import java.util.Comparator;

public class FileExt{ public static void main(String[] args){ String[] tests = {"text.txt", "text.TXT", "test.tar.gz", "test/test2.exe", "test\\test2.exe", "test", "a/b/c\\d/foo"}; String[] exts = {".txt",".gz","",".bat"};

System.out.println("Extensions: " + Arrays.toString(exts) + "\n");

for(String test:tests){ System.out.println(test +": " + extIsIn(test, exts)); } }

public static boolean extIsIn(String test, String... exts){ int lastSlash = Math.max(test.lastIndexOf('/'), test.lastIndexOf('\\')); //whichever one they decide to use today String filename = test.substring(lastSlash + 1);//+1 to get rid of the slash or move to index 0 if there's no slash

//end of the name if no dot, last dot index otherwise int lastDot = filename.lastIndexOf('.') == -1 ? filename.length() : filename.lastIndexOf('.'); String ext = filename.substring(lastDot);//everything at the last dot and after is the extension

Arrays.sort(exts);//sort for the binary search

return Arrays.binarySearch(exts, ext, new Comparator<String>() { //just use the built-in binary search method @Override //it will let us specify a Comparator and it's fast enough public int compare(String o1, String o2) { return o1.compareToIgnoreCase(o2); } }) >= 0;//binarySearch returns negative numbers when it's not found } } </lang>

Output:
Extensions: [.txt, .gz, , .bat]

text.txt: true
text.TXT: true
test.tar.gz: true
test/test2.exe: false
test\test2.exe: false
test: true
a/b/c\d/foo: true

Using FileNameExtensionFilter

Works with: Java version 6+

This version is the same as the main version only replace the definition for extIsIn with: <lang java5>public static boolean extIsIn(String test, String... exts){ for(int i = 0; i < exts.length; i++){ exts[i] = exts[i].replaceAll("\\.", ""); } return (new FileNameExtensionFilter("extension test", exts)).accept(new File(test)); }</lang> It would be one line if not for the dot requirement. FileNameExtensionFilter requires that the extensions have no dots. It also requires that the extensions contain characters (i.e. not the empty string) so that test would need to be removed.

Perl 6

<lang perl6>sub ext-in-list(@ext,@files) {

   for @files {
       when / :i @ext $ /      { say "True\t$_" }
       when / '.' <-[/.]>+ $ / { say "False\t$_" }
       default                 { say "----\t$_" }
   }

}

ext-in-list

   «
       .c
       .C#
       .o
       .yup
       .½xy
      '. embedded blanks '
   »,
   «
       foo.c
       foo.C
       foo.C++
       foo.c#
       foo.zkl
       somefile
      'holy smoke'
       afile.
       /a/path/to/glory.yup/or_not
       funny...
       unusual.½xy
      'fly_in_the_ointment. embedded blanks '
   »;</lang>
Output:
True	foo.c
True	foo.C
False	foo.C++
True	foo.c#
False	foo.zkl
----	somefile
----	holy smoke
----	afile.
----	/a/path/to/glory.yup/or_not
----	funny...
True	unusual.½xy
True	fly_in_the_ointment. embedded blanks 

Python

<lang Python> import os

def isExt(filename, extensions):

   return os.path.splitext(filename.lower())[-1] in [e.lower() for e in extensions]

</lang>

REXX

Programming note:   extra code was added to:

  • display some error/warning messages
  • handle the case of the filename having a path
  • handle the case of different types of path separators
  • handle the case of the filename having no file extension
  • handle cases of the filename ending in a period
  • handle cases of the filename ending in multiple periods
  • handle cases of blanks in the filename and/or extension

<lang rexx>/*REXX program displays if a filename has a known extension (per a list)*/ /*╔════════════════════════════════════════════════════════════════════╗

 ║ The list of extensions below have blanks encoded as  'ff'x.        ║
 ║ The extension pointed to has a  'ff'x  after the period──────────┐ ║
 ║ (which is used to indicate a true blank,  due to                 │ ║
 ║ REXX's use of blanks in lists as delimiters).                    │ ║
 ╚══════════════════════════════════════════════════════════════════↓═╝*/

extensions='.bat .cmd .com .dat .dll .exe .ini .jpg .jpeg .log .txt . ys'

                                      /* [↑]  above would be some EXTs.*/

parse arg fn /*get the filename from the C.L. */ if fn== then exit /*No fn specified? Then exit.*/ afn=translate( fn, '/', "\") /*handle both versions of pathSep*/ afn=translate(afn, 'ff'x, " ") /*··· and also handle true blanks*/ afn=substr(afn,lastpos('/',afn)+1) /*pick off the filename from path*/ p=lastpos('.',afn) /*find the last position of a dot*/ if p==0 | p==length(afn) then do /*no dot or dot is at end of name*/

                              say 'Filename ' fn " has no extension."
                              exit
                              end

ft=substr(afn,p) /*pickoff the fileType (fileExt).*/ say 'ft=' ft upper ft extensions /*uppercase a couple of REXX vars*/ if wordpos(ft,extensions)==0 then _='an unknown'

                             else _= 'a known'

say 'Filename ' fn "has" _ 'extension.'</lang>

Ruby

<lang ruby>extensions = [".c",".o",""] ["foo.C","foo.zkl","foo","foo."].each do |f|

 puts "%5s : %s" % [extensions.include?( File.extname(f).downcase ), f]

end</lang>

Output:
 true : foo.C
false : foo.zkl
 true : foo
 true : foo.

Scala

<lang Scala>def isExt(fileName: String, extensions: List[String]): Boolean = {

   extensions.map { _.toLowerCase }.exists { fileName.toLowerCase endsWith _ }

}</lang>

Tcl

<lang tcl># Note that these are already all in lower case set exts {".txt" ".gz" ".bat" ".c" ".c++" ".exe" ".pdf"} set filenames {

   text.txt
   text.TXT
   test.tar.gz
   test/test2.exe
   test\\test2.exe
   test
   a/b/c\\d/foo
   foo.c
   foo.C
   foo.C++
   foo.c#
   foo.zkl
   document.pdf

}

foreach name $filenames {

   set ext [file extension $name]
   if {[string tolower $ext] in $exts} {

puts "'$ext' (of $name) is present"

   } else {

puts "'$ext' (of $name) is absent"

   }

}</lang>

Output:
'.txt' (of text.txt) is present
'.TXT' (of text.TXT) is present
'.gz' (of test.tar.gz) is present
'.exe' (of test/test2.exe) is present
'.exe' (of test\test2.exe) is present
'' (of test) is absent
'' (of a/b/c\d/foo) is absent
'.c' (of foo.c) is present
'.C' (of foo.C) is present
'.C++' (of foo.C++) is present
'.c#' (of foo.c#) is absent
'.zkl' (of foo.zkl) is absent
'.pdf' (of document.pdf) is present

zkl

<lang zkl>var exts=T(".c",".o",""); fcn hasExtension(fname){ exts.holds(File.splitFileName(fname)[3].toLower()) } T("foo.C","foo.zkl","foo","foo.").apply(hasExtension).println();</lang>

Output:
L(True,False,True,True)