最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

jquery - Get all parent paths from Path String - Javascript - Stack Overflow

programmeradmin4浏览0评论

I need some advice concerning string manipulation. This is a possible string:

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

What I need is an array with the following in it:

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

So to clarify what this array should contain: All parent paths to the last file or folder. The last file or folder is excluded in the array.

I know I can split the string at "/" and then could iterate over the array, concatenate strings and delete the last entry from the array. This method I would call recursively until there is no element in the array left. The concatenated string would then be saved at every iteration to a new array which would hold the desired result at the end......

However I asked me how to do it very clean and simple and I am sure someone of you can e up with a superb solution :)

EDIT Here is my current solution I came up with just now:

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();
    }
}

I need some advice concerning string manipulation. This is a possible string:

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

What I need is an array with the following in it:

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

So to clarify what this array should contain: All parent paths to the last file or folder. The last file or folder is excluded in the array.

I know I can split the string at "/" and then could iterate over the array, concatenate strings and delete the last entry from the array. This method I would call recursively until there is no element in the array left. The concatenated string would then be saved at every iteration to a new array which would hold the desired result at the end......

However I asked me how to do it very clean and simple and I am sure someone of you can e up with a superb solution :)

EDIT Here is my current solution I came up with just now:

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();
    }
}
Share Improve this question edited Feb 13, 2015 at 15:21 dehlen asked Feb 13, 2015 at 15:11 dehlendehlen 7,3915 gold badges44 silver badges72 bronze badges 2
  • Is the URL always in the exact same format? – Dieterg Commented Feb 13, 2015 at 15:21
  • its more a file path then an URL but yes. It will always begin with a / and always end without a slash. Just the number of elements in the path can vary (like "/branches/test" or "/trunk/test2/anotherElement") – dehlen Commented Feb 13, 2015 at 15:23
Add a ment  | 

8 Answers 8

Reset to default 4

Here's a pact solution, but it may not be as clear as @somethinghere 's:

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'));

Update

Thanks for the ments. Here's a more pact version, which doesn't require splitting or shifting:

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'));

Update #2

And just for giggles, a third solution, which should be more legible than my others, but still a little slower than @somethinghere 's:

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'));

This will do the trick:

/* 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] + "/")
    }
}

This will include / as a path, which is technically a path. If you don't want that, you can use this line instead at the initialisation to exclude any simple paths like that:

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

If you do the above though, beware that your loop will throw an error as endPaths[i-1] will be undefined when your loop starts running, you will have to do a check inside your for loop:

/* 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] + "/")

And, for a little more variety, a recursive, RegExp-based solution:

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)
    }
}

The function takes in:

  1. the test string,
  2. a pattern to "ignore" during the match
  3. the array to turn the results to

The "ignore" pattern will start out as a blank string, but, during every iteration, will contain the previously matched directory level. This string is used as the beginning of the matching pattern, which then adds a RegExp pattern to the end, containing a RegExp pattern to match a forward slash and one or more non-slash characters.

The match is captured in the results array and, if it does not equal the test string, is passed into the iterateMatch function again as the next "ignore" pattern (along with the original test string and results array), so that the match starts looking at the next level down.

When called like this, with your test string:

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

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

iterateMatch(sTestString, sCurrPattern, aResults);

console.log(aResults);

. . . the result is:

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

This reduce solved my use-case (without a preceding /):

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"] 

Or this one-liner if you're absolutely bonkers:

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

Not at all short and not at all elegant... A bit different approach...

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

Here's my take on it. Using a little jQuery to help us out makes for a nice concise function (even if it is a bit inefficient).

    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'));
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Try

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)
<pre></pre>

Not particularly efficient but fairly readable.

path
  .split('/')
  .filter(s => !!s)
  .reduce(
    (acc, val, i) => acc.toSpliced(0, 0, acc[0] + (i ? '/' : '') + val),
    ['/'],
  )
  .toReversed();
发布评论

评论列表(0)

  1. 暂无评论