首页 > 试题广场 >

Unix路径简化

[编程题]Unix路径简化
  • 热度指数:1774 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
简化 Unix 风格的路径,需要考虑的包括 "/../", "//", "/./" 等情况

输入描述:
Unix 风格的路径


输出描述:
简化后的Unix 风格路径
示例1

输入

/a/./b/../../c/

输出

/c
将连续的/替换成一个 /,然后用/切分字符串为一个字符串数组进行遍历:空串不处理;如果遇到 .,相当于当前目录,直接跳过;如果遇到 ..,相当于退到上级目录,进行一次弹栈,弹出一级的目录名,但在栈为空的情况下相当于已经到了根目录,退无可退,什么操作都不做。
最后栈中剩下的目录名都用 连接起来即可
path = input().replace("//", '/').split('/')
stack = []
for directory in path:
    if not directory: continue
    if directory == '..':
        if stack:
            stack.pop()
        else:
            continue
    elif directory == '.':
        continue
    else:
        stack.append(directory)
print('/' + '/'.join(stack))

发表于 2021-04-07 11:55:57 回复(0)
python3

class Solution:
    def simplifyPath(self, path: str) -> str:
        stack = []
        path = path.split("/")

        for item in path:
            if item == "..":
                if stack : stack.pop()
            elif item and item != ".":
                stack.append(item)
        return "/" + "/".join(stack)

发表于 2019-08-17 17:30:57 回复(0)
使用stringstream分割字符串,将结果存到栈中,如果当前字符串为"."或者空,
不进行任何操作,如果当前字符串为".."则栈中弹出一个元素,否则进栈。
#include <iostream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <climits>
#include <string>
#include <stack>

using namespace std;

int main()
{
    string input;
    cin >> input;
    stringstream ss(input);
    stack<string> st;
    string tmp;
    while (getline(ss, tmp, '/')) {
        if (tmp == "." || tmp == "") {
            continue;
        } else if (tmp == "..") {
            if (!st.empty())
                st.pop();
        } else {
            st.push(tmp);
        }
    }
    string res = "";
    if (st.empty()) {
        cout << "/" << endl; return 0;
    }
    while (!st.empty()) {
        res = st.top() + res;
        res = "/" + res;
        st.pop();
    }
    cout << res << endl;
    return 0;
}

发表于 2019-05-18 13:22:30 回复(0)
import java.util.Scanner;
import java.util.Stack;

public class Main {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String s = sc.next();
            String[] strs = s.split("/");
            Stack<String> stack = new Stack<String>();
            for (int i = 0; i < strs.length; i++) {
                String cur = strs[i];
                if (cur.equals(".") || cur.equals("")) {
                    continue;
                } else if (cur.equals("..")) {
                    if(!stack.isEmpty()) {
                        stack.pop();
                    }
                } else {
                    stack.push(cur);
                }
            }
            String res = "";
            while (!stack.isEmpty()) {
                String cur = stack.pop();
                res = "/" + cur + res;
            }
            if(res.equals("")) {
                res = "/";
            }
            System.out.println(res);
        }
        sc.close();

    }

}
发表于 2018-05-21 10:11:45 回复(0)
1、/表示根目录,linux/uinx下目录是成树结构的,根目录即树的根,不可能再继续向上了。
2、. 表示当前目录。
3、.. 表示上级目录。
4、/也用于目录间的分隔,如/a/b 表示根目录下的a路径下的b路径;a/b 表示当前目录下的a路径下的b路径。
5、/用于分隔符号时,个数可多可少,如//a/////b和/a/b是一样的。注意//a/////b和a/b不一样,因为前者有个根目录。结尾的/无意义,如a/b和a/b/是一样的。

我们可以用入栈出栈来模拟进入目录退出目录,但是stl 的stack又不适用,因为stack只能从栈顶依次输出,处理笔记麻烦,所以用vector。一个临时变量str,用于保存两个/ 之间的字符串。
1、如果str == "."什么也不做
2、如果str == ".."出栈
3、否则,str入栈。

这道题有三处坑人的地方:
1、出栈前要判断栈不为空,因为在linux、unix下,命令 cd /../../是合法的,结果是进入根目录,不可能在向上了。
2、入栈前要判断str是否是空字符串,因为要排除类似//a/////b的这种情况。
3、最后结果中,如果栈是空的,也要输出一个 /

#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char *argv[])
{
    int i, j, len;
    string input, str;
    vector<string> dir;
    vector<string> :: iterator it;
    
    cin >> input;
    len = input.length();
    for(i = 0; i < len; i++) //遍历字符串,找到所有/之间的子串
    {
        if(input[i] == '/')
        {
            j = i + 1;
            while(j < len && input[j] != '/')
            {
                j++;
            }
            if(i + 1 < len)
            {
                str = input.substr(i + 1, j - i - 1);//取/之间的子串
                if(str == "..")
                {
                    if(!dir.empty()) //出栈前判断栈不空,否则会段错误。
                    {
                        dir.pop_back();
                    }
                }
                else if(str == ".")
                {
                    ;
                }
                else if(!str.empty()) //入栈前判断子串不是空的
                {
                    dir.push_back(str);
                }
            }
            i = j - 1;
        }
    }
    if(dir.empty()) //如果结果栈是空的,也要输出一个 /
    {
        cout << "/";
    }
    else
    {
        for(it = dir.begin(); it != dir.end(); it++)
        {
            cout << "/" << (*it);
        }
    }
    cout << endl;
    
    return 0;
}

发表于 2019-01-27 09:36:33 回复(1)
#include <bits/stdc++.h>
using namespace std;

int main(){
    string s;
    vector<string> r;
    cin>>s;
    int l = s.length();
    for(int i=0;i<l;i++){
        if(s[i] == '/'){
            int j = i+1;
            while(j<l && s[j]!='/')
                j++;
            j--;
            if(i+1 < l){
                string t = s.substr(i+1, j-i);
                if(t == ".."){
                    if(!r.empty())
                        r.pop_back();
                }else if(t != "." && t!="")
                    r.push_back(t);
            }
            i = j;
        }
    }
    if(r.empty())
        printf("/");
    else
        for(auto &t: r)
            printf("/%s", t.c_str());
    return 0;
}

发表于 2020-11-22 02:17:19 回复(0)
import os
print(os.path.normpath(input()))
今天笔试遇到了这题,用栈A了半天没考虑../的情况,还不如直接不讲武德用os
发表于 2023-06-27 22:44:42 回复(0)
import java.nio.file.Paths;
import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        System.out.print(Paths.get(s).normalize().toString());
    }
}

发表于 2019-10-11 17:27:44 回复(0)
import re
path_input = input().strip()
dir_stack = []
name_lst = re.split('/+', path_input)
name_lst = [i for i in name_lst if i != '.'and i != '']
for i in name_lst:
    if i != '..':
        dir_stack.append(i)
    else:
        if len(dir_stack) != 0:
            dir_stack.pop()
print('/' + '/'.join(dir_stack))
发表于 2019-04-04 16:53:34 回复(0)
您的代码已保存
答案错误:您提交的程序没有通过所有的测试用例
case通过率为40.00%

用例:
/.x/.a/y/.//

对应输出应该为:

/.x/.a/y

你的输出为:

/y

这种用例是什么情况,求解
发表于 2019-03-25 23:16:19 回复(1)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;

/**
 * @author wylu
 */
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        LinkedList<String> stack = new LinkedList<>();
        for (String s : br.readLine().split("/")) {
            if (s.equals("..") && !stack.isEmpty()) stack.removeLast();
            else if (!s.equals("") && !s.equals(".") && !s.equals("..")) stack.addLast(s);
        }
        System.out.println("/" + String.join("/", new ArrayList<>(stack)));
    }
}

发表于 2019-03-11 20:11:50 回复(2)
import re
ss=raw_input().strip('\n')
arr=re.split('/+',ss)
tp1=[]
for  i in arr:
    if i != '.':
        tp1.append(i)
tp2=[]
for j in tp1:
    if j !='..':
        tp2.append(j)
    else:
        if len(tp2)==1:
            continue
        else:
            tp2.pop()
res='/'.join(tp2)
if len(res)==1:
    print res
else:
    print res.rstrip('/')

编辑于 2018-09-12 22:07:32 回复(0)
为什么换成 str == ".."就会报错呢?不是一样吗,而且 == 这种还会判断地址
发表于 2018-08-29 23:46:47 回复(0)
#include <iostream>
#include <string>
#include <stack>
#include <deque>
using namespace std;
int main(){
    string input;
    while(cin>>input){
        stack<char> temp;
        for(int i = 0;i < input.size();i++){
            if((i+1 < input.size())&&(input[i]=='/'&&input[i+1]=='/')){
                continue;
            }
            else if((i+2 < input.size())&&((input[i]=='/'&&input[i+1]=='.'&&input[i+2]=='/')))
            {
                i += 1;
                continue;
            }
            else if((i+3 < input.size())&&(input[i]=='/'&&input[i+1]=='.'&&input[i+2]=='.'&&input[i+3]=='/')){
                for(;temp.size() > 0;){
                    if(temp.top()!='/'){
                        temp.pop();
                    }
                    else
                        break;
                }
                if(temp.size() > 0)
                    temp.pop();
                i += 2;
            }// \..情况
            else
                temp.push(input[i]);
        }
        deque<char> temp0;
        int j = temp.size();
        for(int i = 0;i < j;i++){
            temp0.push_front(temp.top());
            temp.pop();
        }
        string res(temp0.begin(),temp0.end());
        j = res.size();
        for(;res.size()>0;)
        if(res[res.size()-1] == '/')
            res.erase(res.end()-1);
        else
            break;
        if(res.size()==0)
            res.push_back('/');
        cout<<res<<endl;
        input.clear();
    }
    return 0;
}
然后居然有一个测试用例是这个,想知道根目录下一直/../../../../这种表达方式是合法路径吗?
             /../x//../../../.x/../.j/../
发表于 2018-05-19 11:20:00 回复(0)