【问题标题】:Get all parent paths from Path String - Javascript从路径字符串获取所有父路径 - Javascript
【发布时间】:2015-04-14 16:07:53
【问题描述】:

我需要一些关于字符串操作的建议。这是一个可能的字符串:

"/branches/projects/MyTool/MyTool/someOtherFolderOrFile"

我需要的是一个包含以下内容的数组:

 ['/branches', '/branches/projects','/branches/projects/MyTool','/branches/projects/MyTool/MyTool']

所以要澄清这个数组应该包含什么:最后一个文件或文件夹的所有父路径。最后一个文件或文件夹被排除在数组中。

我知道我可以在"/" 处拆分字符串,然后可以遍历数组、连接字符串并从数组中删除最后一个条目。这个方法我会递归调用,直到数组中没有元素为止。然后在每次迭代时将连接的字符串保存到一个新数组中,该数组将在最后保存所需的结果......

但是我问我如何做到非常干净和简单,我相信你们中的某个人可以想出一个极好的解决方案:)

编辑 这是我刚刚提出的当前解决方案:

var string = "/branches/projects/MyTool/MyTool/anotherFolderOrFile";
var helperArr = string.split("/");
var endArray = [];

getParentArray();
console.log(endArray);

function getParentArray() {
    if(helperArr.length == 1) {
        return;
    }
    else {
        var helperString = "";
        for(var i = 0;i<helperArr.length;i++) {
            helperString = helperString+helperArr[i];
            if(i!= helperArr.length -1) {
                helperString = helperString+"/";
            }
        }
        endArray.push(helperString);
        helperArr.length = helperArr.length-1;
        getParentArray();
    }
}

【问题讨论】:

  • 网址是否始终采用完全相同的格式?
  • 它更多的是文件路径而不是 URL,但是是的。它总是以 / 开头,并且总是没有斜杠结束。只是路径中的元素数量可能会有所不同(例如“/branches/test”或“/trunk/test2/anotherElement”)

标签: javascript jquery arrays string


【解决方案1】:

这是一个简洁的解决方案,但可能不如@somethinghere 的那么清晰:

var path= '/branches/projects/MyTool/MyTool/someOtherFolderOrFile'.split('/'),
    paths= [];

path.shift();
while(path.length > 1) {
  paths.push((paths[paths.length-1] || '') + '/' + path.shift());
}

alert(paths.join('\r'));

更新

感谢 cmets。这是一个更紧凑的版本,不需要拆分或移动:

var path= '/branches/projects/MyTool/MyTool/someOtherFolderOrFile',
    paths= [],
    i = 1;

while(i = path.indexOf('/',i)+1) {
  paths.push(path.substr(0,i));
}

alert(paths.join('\r'));

更新 #2

只是为了咯咯笑,第三种解决方案应该比我的其他解决方案更清晰,但 still a little slower 比 @somethinghere 的:

var path= '/branches/projects/MyTool/MyTool/someOtherFolderOrFile',
    paths= [],
    i;

for(var i = 1 ; i < path.length ; i++) {
  if(path[i]==='/') paths.push(path.substr(0,i));
}
 
alert(paths.join('\r'));

【讨论】:

  • 也在考虑这样的事情:-)
  • 给你一个赞成票,因为我也喜欢你的回答:)
  • 这里其实有很多好的,但是非常不同的解决方案。 . .
  • 是的,我也喜欢这个,但我确实觉得它不太清晰。使用shift() 是否有优势(例如,与我使用的循环解决方案相比,它会赢得一些资源还是可以忽略不计?)
  • @somethinghere,我同意我的第一个代码比你的更易读。我添加了一个新版本,它避免了太多的数组操作。但是while 循环中的单个等号可能会让一些人感到困惑。
【解决方案2】:

这样就可以了:

/* First split the path at any folders separator ('/')*/
var splitPath = "/branches/projects/MyTool/MyTool/someOtherFolderOrFile".split("/");
/* Initialise a final array to save the paths. Store the first one in there! */
var endPaths = [splitPath[0] + "/"];
/* Check if there are multiple paths available */
if(splitPath.length >= 2){
    /* Run through each and append it to the last saved one, then add it to the results.*/
    for(var i = 1; i <= splitPath.length-1; i++){
        endPaths.push(endPaths[i-1] + splitPath[i] + "/")
    }
}

这将包含/ 作为路径,这在技术上是路径。如果你不想这样,你可以在初始化时使用这一行来排除任何简单的路径:

var endPaths = splitPath[0] != "" ? [splitPath[0] + "/"] : [];

如果您执行上述操作,请注意您的循环将抛出错误,因为当您的循环开始运行时,endPaths[i-1] 将是 undefined,您必须在 for 循环中进行检查:

/* You need to do -2 as you start at 1, but you only want to add paths from 2 upwards.*/
var prevPath = typeof endPaths[i-2] !== "undefined" ? endPaths[i-2] : "";
endPaths.push(prevPath + splitPath[i] + "/")

【讨论】:

  • 谢谢,这看起来比我想出的版本更干净。我会选择这个。
  • 好 :) 我添加了一点,因为我建议忽略最初的 / 可能会引发错误。
  • 好吧,您的编辑对我来说并不适用。但我明白这一点,并将根据我的需要进行调整。无论如何,你帮助我引导我走向正确的方向。
  • 抱歉,因为您在原始 Array 中跳过了一步,您实际上需要返回两步,而不是一步。我已经修改过了。此外,如果您将for 循环到splitPath.length-2 而不是splitPath.length-1,您也可以根据需要排除最后一项。
  • @dehlen - 这实际上是我认为您在原始问题中描述的解决方案。哈哈
【解决方案3】:

而且,为了更多样化,一个递归的、基于 RegExp 的解决方案:

function iterateMatch(testString, currPattern, results) {
    var regexTestPattern = new RegExp("^" + currPattern + "\/[^\/]+");
    results.push(testString.match(regexTestPattern)[0]);

    if (results[results.length - 1] !== testString) {
        iterateMatch(testString, results[results.length - 1], results)
    }
}

函数传入:

  1. 测试字符串,
  2. 匹配期间“忽略”的模式
  3. 将结果转换为的数组

“忽略”模式将以空白字符串开始,但在每次迭代期间,将包含先前匹配的目录级别。此字符串用作匹配模式的开头,然后在末尾添加一个正则表达式模式,其中包含一个正则表达式模式以匹配正斜杠和一个或多个非斜杠字符。

匹配被捕获在结果数组中,如果它不等于测试字符串,则作为下一个“忽略”模式(连同原始测试字符串和结果数组)再次传递给iterateMatch函数,以便比赛开始向下看下一个级别。

当这样调用时,使用你的测试字符串:

var sTestString = "/branches/projects/MyTool/MyTool/someOtherFolderOrFile";

var sCurrPattern = "";
var aResults = [];

iterateMatch(sTestString, sCurrPattern, aResults);

console.log(aResults);

。 . .结果是:

 ["/branches",
  "/branches/projects",
  "/branches/projects/MyTool",
  "/branches/projects/MyTool/MyTool",
  "/branches/projects/MyTool/MyTool/someOtherFolderOrFile"]

【讨论】:

  • 喜欢使用正则表达式:)
【解决方案4】:

这个reduce 解决了我的用例(没有前面的/):

const string = "a/b/c/d";
const stringSplits = string.split('/');
const parentArray = stringSplits.reduce((acc, val, i) => {
  if (i === 0) return [val]
  acc.push( acc[i-1] + '/' + val )
  return acc
}, []);

// returns ["a", "a/b", "a/b/c", "a/b/c/d"] 

如果你绝对是疯子,也可以使用这个单线:

const parentArray = "a/b/c/d".split('/').reduce((acc, val, i) => i === 0 ? [val] : [].concat(acc, acc[i-1] + '/' + val ), []);

【讨论】:

    【解决方案5】:

    一点也不短,一点也不优雅……有点不同的方法……

    function split_string_to_path( str ) {
      if (typeof str == "undefined")
        return false; // return, if no string
    
      split_path = str.split("/"); // splitted string
    
      result_arr = []; // result paths into this variable
      tmp_arr = []; // temporary, for join
    
      for( i = 0; i < split_path.length; i++ ) { // loop through all elements
        tmp_arr.push( split_path[i] ); // push element
        result_path = tmp_arr.join( "/" );
    
        if ( result_path.length > 0 )
          result_arr.push( tmp_arr.join( "/" ) ); // join tmp arr to path and add it to result_arr
      }
    
      return result_arr;
    }
    
    split_result = split_string_to_path( "/branches/projects/MyTool/MyTool/someOtherFolderOrFile" ); // run function
    
    console.log( split_result ); // output on console
    

    【讨论】:

    • 有很多改进,例如,你可以简单地使用if(!str),而不是if(typeof str === "undefined"),因为str 将是falsy,但可以检查(如其在功能)。由于变量str在拆分后没有被使用,您可以将split()本身重写为str,以避免创建任何变量,从而节省资源。另外,这只是一个旁注,但我认为你的函数应该命名为split_path_to_string :)
    【解决方案6】:

    这是我的看法。使用一点 jQuery 来帮助我们实现了一个非常简洁的函数(即使它有点低效)。

        function getParentArray(path) {
            // split up on the forward slashes
            var splitPath = path.split('/');
            // Don't need the last part of the path
            splitPath.pop();
            // put an ever growing slice of the original path into a new array
            return $.map(splitPath, function(value, i) {
                return '/' + splitPath.slice(1, i + 1).join('/');
            }).splice(1);
        }
    
        var samplePath = '/branches/projects/MyTool/MyTool/someOtherFolderOrFile';
        var parentArray = getParentArray(samplePath);
    
        alert(parentArray.join('\n'));
    &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

    【讨论】:

      【解决方案7】:

      试试

      var str = "/branches/projects/MyTool/MyTool/someOtherFolderOrFile"
      , d = "/"
      , arr = str.split(d).filter(Boolean)
      , res = arr.map(function(val, i) {
                  return i < 1 ? d + val : d + arr.slice(0, i).join(d) + d + arr[i] 
        }).slice(0, arr.length - 1);
      

          var str = "/branches/projects/MyTool/MyTool/someOtherFolderOrFile"
          , d = "/"
          , arr = str.split(d).filter(Boolean)
          , res = arr.map(function(val, i) {
                    return i < 1 ? d + val : d + arr.slice(0, i).join(d) + d + arr[i] 
            }).slice(0, arr.length - 1); 
      
      document.querySelectorAll("pre")[0].innerText = JSON.stringify(res, null, 4)
      &lt;pre&gt;&lt;/pre&gt;

      【讨论】:

        猜你喜欢
        • 2014-10-16
        • 2018-11-30
        • 2019-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-27
        • 2013-07-07
        • 1970-01-01
        相关资源
        最近更新 更多