在Javascript中需要一个basename函数

时间:2010-09-29 09:40:17

标签: javascript string

我需要一个简短的基本名称功能(单线程?)用于Javascript:

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

那应该剥离路径和任何扩展名。

更新: 对于开头的点将很好地视为“特殊”文件

basename("/a/folder/.file.a.ext") -> ".file.a"
basename("/a/folder/.file.ext") -> ".file"
basename("/a/folder/.file") -> ".file" # empty is Ok
basename("/a/folder/.fil") -> ".fil"  # empty is Ok
basename("/a/folder/.file..a..") -> # does'nt matter

19 个答案:

答案 0 :(得分:65)

function baseName(str)
{
   var base = new String(str).substring(str.lastIndexOf('/') + 1); 
    if(base.lastIndexOf(".") != -1)       
        base = base.substring(0, base.lastIndexOf("."));
   return base;
}

如果您可以同时使用/\作为分隔符,则必须更改代码以再添加一行

答案 1 :(得分:61)

function basename(path) {
   return path.split('/').reverse()[0];
}

将路径分解为组件目录和文件名,然后返回最后一块(文件名),这是该数组的最后一个元素。

答案 2 :(得分:19)

上述任何一项工作虽然他们不尊重速度/记忆: - )。

更快/更简单的实现应该使用尽可能少的函数/操作。 RegExp是一个糟糕的选择,因为它实际上可以实现相同的结果但是更容易消耗大量资源。

当您想要包含扩展名的文件名(实际上这是基本名称的正式定义)时的实现:

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

如果你需要一个自定义基本名称实现,我必须删除扩展名,我建议使用特定的扩展名剥离函数,你可以随时调用它。

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

用法示例:

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

它们是分开的,您可以将它们组合起来以获得3种不同的东西:剥离扩展,获取实名,获取自定义基本名称。我认为它比其他方法更优雅。

答案 3 :(得分:11)

如果可以,也许尝试使用现有的包。 http://nodejs.org/api/path.html

var path = require('path');
var str = '/path/to/file/test.html'

var fileNameStringWithoutExtention = path.basename(str, '.html');
// returns 'test'

// let path determine the extension
var fileNameStringWithoutExtention = path.basename(str, path.extname(str));
// returns 'test'

其他例子:

var pathString = path.dirname(str);
var fileNameStringWithExtention = path.basename(str);
var fullPathAndFileNameString = path.join(pathString, fileNameString);

答案 4 :(得分:6)

 basename = function(path) {
    return path.replace(/.*\/|\.[^.]*$/g, '');
 }

替换以斜线.*\/或点结尾的任何内容 - 一些非圆点 - 结束\.[^.]*$没有任何内容

答案 5 :(得分:3)

使用现代(2020)js代码:

function basename (path) {
  return path.substring(path.lastIndexOf('/') + 1)
}
console.log(basename('/home/user/file.txt'))

答案 6 :(得分:2)

就像@ 3DFace评论说的那样:

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

或者如果你喜欢原型:

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

测试:

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

将返回" need-a-basename-function-in-javascript"。

享受!

答案 7 :(得分:1)

另一个好的解决方案:

Option()

来自:http://locutus.io/php/filesystem/basename/

答案 8 :(得分:1)

快速,不带正则表达式,适用于路径类型“ /”和“ \”。同时获取扩展名:

function baseName(str)
{
    let li = Math.max(str.lastIndexOf('/'), str.lastIndexOf('\\'));
    return new String(str).substring(li + 1);
}

答案 9 :(得分:1)

与上面提供的错误信息相反,正则表达式非常有效。需要注意的是,如果可能的话,他们应该处于一个位置,以便在程序的生命周期中编译一次。

这是一个提供 dirname basename 的解决方案。

const rx1 = /(.*)\/+([^/]*)$/;    // (dir/) (optional_file)
const rx2 = /()(.*)$/;            // ()     (file)

function dir_and_file(path) {
  // result is array with
  //   [0]  original string
  //   [1]  dirname
  //   [2]  filename
  return rx1.exec(path) || rx2.exec(path);
}
// Single purpose versions.
function dirname(path) {
  return (rx1.exec(path) || rx2.exec(path))[1];
}
function basename(path) {
  return (rx1.exec(path) || rx2.exec(path))[2];
}

至于性能,我还没有测量过,但是我希望这个解决方案与本页面上其他解决方案的速度相同,但这个解决方案做得更多。帮助实际表现的事实是rx1将匹配大多数实际路径,因此很少执行rx2

这是一些测试代码。

function show_dir(parts) {
  console.log("Original str :"+parts[0]);
  console.log("Directory nm :"+parts[1]);
  console.log("File nm      :"+parts[2]);
  console.log();
}
show_dir(dir_and_file('/absolute_dir/file.txt'));
show_dir(dir_and_file('relative_dir////file.txt'));
show_dir(dir_and_file('dir_no_file/'));
show_dir(dir_and_file('just_one_word'));
show_dir(dir_and_file('')); // empty string
show_dir(dir_and_file(null)); 

以下是测试代码的结果:

# Original str :/absolute_dir/file.txt
# Directory nm :/absolute_dir
# File nm      :file.txt
# 
# Original str :relative_dir////file.txt
# Directory nm :relative_dir
# File nm      :file.txt
# 
# Original str :dir_no_file/
# Directory nm :dir_no_file
# File nm      :
# 
# Original str :just_one_word
# Directory nm :
# File nm      :just_one_word
# 
# Original str :
# Directory nm :
# File nm      :
# 
# Original str :null
# Directory nm :
# File nm      :null

顺便说一句,"节点"有一个内置的模块叫做" path"有" dirname"和" basename"。 Node' path.dirname()"功能准确地模仿" bash"贝壳" dirname,"但这样好吗?这就是它的作用:

  1. '.'(空字符串)时生成path==""(点)。
  2. '.'时生成path=="just_one_word"(点)。
  3. '.'时生成path=="dir_no_file/"(点)。
  4. 我更喜欢上面定义的函数的结果。

答案 10 :(得分:1)

function basename(url){
    return ((url=/(([^\/\\\.#\? ]+)(\.\w+)*)([?#].+)?$/.exec(url))!= null)? url[2]: '';
}

答案 11 :(得分:0)

如果您的原始字符串或文本文件包含单个反斜杠字符,则可以使用' \'来找到它。 在我的情况下,我使用javascript找到" \ N"的索引。从文本文件。和str.indexOf(' \ N');帮我找到从源文件中读取的原始字符串中的\ N. 希望它有所帮助。

答案 12 :(得分:0)

<强>更新

使用前向/和反斜杠\单一或双精的改进版本表示以下任一项

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

请参阅下面的工作演示

&#13;
&#13;
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>');
});
&#13;
<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>
&#13;
&#13;
&#13;

更简单的解决方案可能是

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

工作示例:https://jsfiddle.net/Smartik/2c20q0ak/1/

答案 13 :(得分:0)

my_basename('http://www.example.com/dir/file.php?param1=blabla#cprod',   '/',  '?');
// returns:  file.php


代码:

function my_basename(str, DirSeparator, FileSeparator) { var x= str.split(DirSeparator); return x[x.length-1].split(FileSeparator)[0];}

答案 14 :(得分:0)

使用ES6箭头功能漂亮地一行:

var basename = name => {return /([^\/]*)\.[^.]*$/gm.exec(name)[1];}

答案 15 :(得分:0)

这是我在基本js文件中使用的实现。

// BASENAME

Window.basename = function() {
    var basename = window.location.pathname.split(/[\\/]/);
    return basename.pop() || basename.pop();
}

答案 16 :(得分:0)

基本名称目录名称的JavaScript函数:

        line = "\t".join(["{}"] * len(records[0]))

        f = IteratorFile(line.format(*list(r.values())) for r in records)

示例:

function basename(path) {
     return path.replace(/.*\//, '');
}

function dirname(path) {
     return path.match(/.*\//);
}

请参见reference

答案 17 :(得分:0)

定义灵活的basename实现

尽管有所有答案,但我仍然必须制定符合以下条件的自己的解决方案:

  1. 它是完全可移植的,并且可以在任何环境中工作(因此,Node的path.basename不会这样做)
  2. 同时使用两种分隔符(/\
  3. 允许混合分离器-例如a/b\c(这与Node的实现不同,Node的实现改为尊重底层系统的分隔符)
  4. 如果路径以分隔符(即getBaseName('a/b/c/') === 'c')结尾,则不会返回空路径

代码

(确保在运行代码段之前打开控制台)

/**
 * 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 ? '✅' : '❌'
  };
}));

答案 18 :(得分:0)

使用正则表达式非常简单:

function basename(input) {
   return input.split(/\.[^.]+$/)[0];
}

说明:

匹配单个点字符,后跟除点([^.])之外的任何字符,一次或多次(+),绑定到字符串的末尾($

然后根据此匹配条件拆分字符串,并返回第一个结果(即匹配前的所有内容)。

[编辑] D'哦。误读了这个问题 - 他也希望脱离这条道路。哦,无论如何,这回答了一半问题。