File extension is in extensions list: Difference between revisions

From Rosetta Code
Content added Content deleted
(jq)
Line 255: Line 255:
It would be one line if not for the dot requirement. <code>FileNameExtensionFilter</code> 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.
It would be one line if not for the dot requirement. <code>FileNameExtensionFilter</code> 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.


=={{header|jq}}==
{{works with|jq|1.4}}
<lang jq># Input: filename
# Output: if the filename ends with one of the extensions (ignoring case), output that extension; else output null.
# Assume that the list of file extensions consists of lower-case strings, including a leading period.
def has_extension(list):
def ascii_downcase: explode | map( if 65 <= . and . <= 90 then . + 32 else . end) | implode;
rindex(".") as $ix
| if $ix then (.[$ix:] | ascii_downcase) as $ext
| if list | index($ext) then $ext else null end
else null
end;</lang>
'''Examples:'''
<lang jq>("c:", "txt", "text.txt", "text.TXT", "foo.c", "foo.C++", "document.pdf")
| has_extension([".txt", ".c"]) as $ext
| if $ext then "\(.) has extension \($ext)"
else "\"\(.)\" does not have an admissible file extension"
end</lang>

{{out}}
<lang jq>$ jq -r -n -f File_extension_is_in_extensions_list.jq
"c:" does not have an admissible file extension
"txt" does not have an admissible file extension
text.txt has extension .txt
text.TXT has extension .txt
foo.c has extension .c
"foo.C++" does not have an admissible file extension
"document.pdf" does not have an admissible file extension</lang>
=={{header|Perl 6}}==
=={{header|Perl 6}}==
<lang perl6>sub ext-in-list(@ext,@files) {
<lang perl6>sub ext-in-list(@ext,@files) {

Revision as of 08:10, 10 June 2015

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


C

According to this, an extension is whatever comes after the last dot. Dotless filename won't match anything.

<lang c>#include <stdio.h>

  1. include <string.h>
  2. include <stdbool.h>

/* this should be the way we check if we can use posix/bsd strcasecmp */

  1. if !defined(_BSD_SOURCE) && !defined(_DEFAULT_SOURCE)
  2. include <ctype.h>

int strcasecmp(const char *s1, const char *s2) {

 for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)
   if(*s1 == 0)
     return 0;
 return *(unsigned char *)s1 < *(unsigned char *)s2 ? -1 : 1;

}

  1. else
  2. include <strings.h>
  3. endif


bool ext_is_in_list(const char *filename, const char *extlist[]) {

 size_t i;
 const char *ext = strrchr(filename, '.');
 if (ext) {
   for (i = 0; extlist[i] != NULL; ++i) {
     if (strcasecmp(ext, extlist[i]) == 0)

return true;

   }
 }
 return false;

}


// testing const char *fnames[] = {

   "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",
   NULL

};

const char *exts[] = {

   ".txt", ".gz", ".bat", ".c", 
   ".c++", ".exe", ".pdf",
   NULL

};

int main(void) {

 size_t i;
 for (i = 0; fnames[i]; ++i) {
   printf("%s: %s\n", fnames[i], 

ext_is_in_list(fnames[i], exts) ? "yes" : "no");

 }
 return 0;

} </lang>

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.

jq

Works with: jq version 1.4

<lang jq># Input: filename

  1. Output: if the filename ends with one of the extensions (ignoring case), output that extension; else output null.
  2. Assume that the list of file extensions consists of lower-case strings, including a leading period.

def has_extension(list):

 def ascii_downcase: explode | map( if 65 <= . and . <= 90 then . + 32  else . end) | implode;
 rindex(".") as $ix
 | if $ix then (.[$ix:] | ascii_downcase) as $ext
      | if list | index($ext) then $ext else null end
   else null
   end;</lang>

Examples: <lang jq>("c:", "txt", "text.txt", "text.TXT", "foo.c", "foo.C++", "document.pdf") | has_extension([".txt", ".c"]) as $ext | if $ext then "\(.) has extension \($ext)"

 else "\"\(.)\" does not have an admissible file extension"
 end</lang>
Output:

<lang jq>$ jq -r -n -f File_extension_is_in_extensions_list.jq "c:" does not have an admissible file extension "txt" does not have an admissible file extension text.txt has extension .txt text.TXT has extension .txt foo.c has extension .c "foo.C++" does not have an admissible file extension "document.pdf" does not have an admissible file extension</lang>

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>

Racket

<lang racket>#lang racket/base (require (only-in srfi/13 string-suffix-ci?)

        (only-in racket/format ~a))

(define ((in-extensions-list? extns) f)

 (findf (λ (e) (string-suffix-ci? e f)) extns))

(define e.g.-extns '(".txt" ".gz" ".bat" ".c" ".c++" ".exe" ".pdf")) (define in-e.g.-extns-list? (in-extensions-list? e.g.-extns)) (define file-names

 (list "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"))

(for ((f (in-list file-names)))

 (printf "~a ~a~%" (~a #:width 20 f) (or (in-e.g.-extns-list? f) "[NO EXTENSION]")))</lang>
Output:
c:                   [NO EXTENSION]
txt                  [NO EXTENSION]
text.txt             .txt
text.TXT             .txt
test.tar.gz          .gz
test/test2.exe       .exe
test                 [NO EXTENSION]
foo.c                .c
foo.C                .c
foo.C++              .c++
foo.c#               [NO EXTENSION]
foo.zkl              [NO EXTENSION]
document.pdf         .pdf

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)