File extension is in extensions list
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>
- 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
<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
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)