Need a basename function in Javascript

后端 未结 19 1950
野性不改
野性不改 2020-11-29 02:44

I need a short basename function (one-liner ?) for Javascript:

basename(\"/a/folder/file.a.ext\") -> \"file.a\"
basename(\"/a/folder/file.ext\") -> \"f         


        
相关标签:
19条回答
  • 2020-11-29 03:19

    UPDATE

    An improved version which works with forward / and backslash \ single or double means either of the following

    • \\path\\to\\file
    • \path\to\file
    • //path//to//file
    • /path/to/file
    • http://url/path/file.ext
    • http://url/path/file

    See a working demo below

    let urlHelper = {};
    urlHelper.basename = (path) => {
      let isForwardSlash = path.match(/\/{1,2}/g) !== null;
      let isBackSlash = path.match(/\\{1,2}/g) !== null;
    
      if (isForwardSlash) {
        return path.split('/').reverse().filter(function(el) {
          return el !== '';
        })[0];
      } else if (isBackSlash) {
        return path.split('\\').reverse().filter(function(el) {
          return el !== '';
        })[0];
      }
      return path;
    };
    
    $('em').each(function() {
      var text = $(this).text();
      $(this).after(' --> <strong>' + urlHelper.basename(text) + '</strong><br>');
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <em>http://folder/subfolder/file.ext</em><br>
    <em>http://folder/subfolder/subfolder2</em><br>
    <em>/folder/subfolder</em><br>
    <em>/file.ext</em><br>
    <em>file.ext</em><br>
    <em>/folder/subfolder/</em><br>
    <em>//folder//subfolder//</em><br>
    <em>//folder//subfolder</em><br>
    <em>\\folder\\subfolder\\</em><br>
    <em>\\folder\\subfolder\\file.ext</em><br>
    <em>\folder\subfolder\</em><br>
    <em>\\folder\\subfolder</em><br>
    <em>\\folder\\subfolder\\file.ext</em><br>
    <em>\folder\subfolder</em><br>


    A more simpler solution could be

    function basename(path) {
          return path.replace(/\/+$/, "").replace( /.*\//, "" );
    }
    
    Input                           basename()
    /folder/subfolder/file.ext   --> file.ext
    /folder/subfolder            --> subfolder
    /file.ext                    --> file.ext
    file.ext                     --> file.ext
    /folder/subfolder/           --> subfolder
    

    Working example: https://jsfiddle.net/Smartik/2c20q0ak/1/

    0 讨论(0)
  • 2020-11-29 03:20

    Any of the above works although they have no respect for speed/memory :-).

    A faster/simpler implementation should uses as fewer functions/operations as possible. RegExp is a bad choice because it consumes a lot of resources when actually we can achieve the same result but easier.

    An implementation when you want the filename including extension (which in fact this is the genuine definition of basename):

    function basename(str, sep) {
        return str.substr(str.lastIndexOf(sep) + 1);
    }
    

    If you need a custom basename implementation that has to strip also the extension I would recommend instead a specific extension-stripping function for that case which you can call it whenever you like.

    function strip_extension(str) {
        return str.substr(0,str.lastIndexOf('.'));
    }
    

    Usage example:

    basename('file.txt','/'); // real basename
    strip_extension(basename('file.txt','/')); // custom basename
    

    They are separated such that you can combine them to obtain 3 different things: stripping the extention, getting the real-basename, getting your custom-basename. I regard it as a more elegant implementation than others approaches.

    0 讨论(0)
  • 2020-11-29 03:26
    function basename(url){
        return ((url=/(([^\/\\\.#\? ]+)(\.\w+)*)([?#].+)?$/.exec(url))!= null)? url[2]: '';
    }
    
    0 讨论(0)
  • 2020-11-29 03:28

    Just like @3DFace has commented:

    path.split(/[\\/]/).pop(); // works with both separators
    

    Or if you like prototypes:

    String.prototype.basename = function(sep) {
      sep = sep || '\\/';
      return this.split(new RegExp("["+sep+"]")).pop();
    }
    

    Testing:

    var str = "http://stackoverflow.com/questions/3820381/need-a-basename-function-in-javascript";
    alert(str.basename());
    

    Will return "need-a-basename-function-in-javascript".

    Enjoy!

    0 讨论(0)
  • 2020-11-29 03:28

    A nice one line, using ES6 arrow functions:

    var basename = name => /([^\/\\]*|\.[^\/\\]*)\..*$/gm.exec(name)[1];
    
    0 讨论(0)
  • 2020-11-29 03:31

    Defining a flexible basename implementation

    Despite all the answers, I still had to produce my own solution which fits the following criteria:

    1. Is fully portable and works in any environment (thus Node's path.basename won't do)
    2. Works with both kinds of separators (/ and \)
    3. Allows for mixing separators - e.g. a/b\c (this is different from Node's implementation which respects the underlying system's separator instead)
    4. Does not return an empty path if path ends on separator (i.e. getBaseName('a/b/c/') === 'c')

    Code

    (make sure to open the console before running the Snippet)

    /**
     * Flexible `basename` implementation
     * @see https://stackoverflow.com/a/59907288/2228771
     */
    function getBasename(path) {
      // make sure the basename is not empty, if string ends with separator
      let end = path.length-1;
      while (path[end] === '/' || path[end] === '\\') {
        --end;
      }
    
      // support mixing of Win + Unix path separators
      const i1 = path.lastIndexOf('/', end);
      const i2 = path.lastIndexOf('\\', end);
    
      let start;
      if (i1 === -1) {
        if (i2 === -1) {
          // no separator in the whole thing
          return path;
        }
        start = i2;
      }
      else if (i2 === -1) {
        start = i1;
      }
      else {
        start = Math.max(i1, i2);
      }
      return path.substring(start+1, end+1);
    }
    
    // tests
    console.table([
      ['a/b/c', 'c'],
      ['a/b/c//', 'c'],
      ['a\\b\\c', 'c'],
      ['a\\b\\c\\', 'c'],
      ['a\\b\\c/', 'c'],
      ['a/b/c\\', 'c'],
      ['c', 'c']
    ].map(([input, expected]) => {
      const result = getBasename(input);
      return {
        input, 
        result,
        expected,
        good: result === expected ? '✅' : '❌'
      };
    }));

    0 讨论(0)
提交回复
热议问题