上一篇的blog地址为:http://www.cnblogs.com/life91/p/3313868.html
这几天又参加了一个家公司的笔试题,在最后的编程题中竟然出现了去哪儿网开发的第一题,也就是简化路径值。但是这次做题后,我发现我上次写的那个简化源码有很多问题,并且在这次笔试过程中也没有答对。闲话说完了,进入正题。
上次源码出现的BUG:
1. 将连续重复的多个’/’字符视为一个。例如,”/abac/def//////ef”->”/abac/def/ef”。
2. 根目录的开始字符为’/’,并且根目录的上级目录以及上上级目录都是本身。例如,”/../../../”->”/”。
3. 字符’.’作为后缀名的分割符号出现。例如,”/abc/ef.gif”->”/abc/ef.gif”
4. 以字符’/’作为起始字符。
上述是上次源码出现的BUG。在修正这些BUG中,将增加一个临时空间用于存储原始路径。在拷贝过程中将连续重复出现的’/’变为一个’/’,并且删除”/./”这种情况。同时检查参数路径是否合法,目前仅考虑一种情况:当’.’个数超过2个时,将退出。
1 // preprocess. 2 while ( index < len ) 3 { 4 // merge duplicate character -- '/' 5 for ( cnt = 0; 6 index < len && path[index] == '/'; 7 ++index, ++cnt ); 8 if ( cnt > 0 ) 9 { 10 tmp_path[top++] = '/'; 11 } 12 13 // delete only dot 14 for ( cnt = 0; 15 index < len && path[index] == '.'; 16 ++index, ++cnt ); 17 // Case 1: delete one dot. 18 if ( top > 0 && tmp_path[top - 1] == '/' && cnt == 1 ) 19 { 20 ++index; 21 } 22 // Case 2: copy two dots. 23 else if ( cnt == 2 ) 24 { 25 index -= cnt; 26 } 27 // Case 3: if more than two dots, it is error. 28 else if ( cnt > 2 ) 29 { 30 fprintf( stderr, "Error.\n" ); 31 // Remember: after free memory, this function could leave. 32 free( tmp_path ), tmp_path = NULL; 33 free( result ), result = NULL; 34 return NULL; 35 } 36 37 // copy other characters. 38 while ( index < len && path[index] != '/' ) 39 { 40 tmp_path[top++] = path[index++]; 41 } 42 }
请注意:在异常退出函数时,需要将已分配的两个内存空间释放掉,并且将原始的指针指向NULL。防止内存泄漏问题。
在后续的处理过程中,使用栈的思想来处理。当遇到连续的两个’.’时,将栈中元素弹出。如果当栈中元素全部退出的时候,将重置top节点。
1 // Case 1: the number of '.' is 2; 2 if ( top > 0 && cnt == 2 ) 3 { 4 --top; 5 while ( --top > 0 && result[top] != '/' ); 6 } 7 // Case 2: "game.gif" 8 else if ( top > 0 && result[top - 1] != '/' && cnt == 1 ) 9 { 10 result[top++] = '.'; 11 } 12 // Case 3: "/../../../" -> "/" 13 else if ( top == 0) 14 { 15 ++top; 16 }
完整的源码并提供简单的测试源码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <assert.h> 5 6 7 char *normalize_path( const char *path ) 8 { 9 char *result = NULL; 10 char *tmp_path = NULL; 11 int top = 0; 12 int cnt = 0; 13 int index = 0; 14 int len = 0; 15 16 assert( path != NULL && path[index] != '\0' && path[index] == '/' ); 17 len = strlen( path ); 18 result = (char *) malloc( sizeof(char) * (len + 1) ); 19 assert( result != NULL ); 20 21 tmp_path = (char *) malloc( sizeof(char) * (len + 1) ); 22 if ( tmp_path == NULL ) 23 { 24 free( result ), result = NULL; 25 return NULL; 26 } 27 28 // preprocess. 29 while ( index < len ) 30 { 31 // merge duplicate character -- '/' 32 for ( cnt = 0; 33 index < len && path[index] == '/'; 34 ++index, ++cnt ); 35 if ( cnt > 0 ) 36 { 37 tmp_path[top++] = '/'; 38 } 39 40 // delete only dot 41 for ( cnt = 0; 42 index < len && path[index] == '.'; 43 ++index, ++cnt ); 44 // Case 1: delete one dot. 45 if ( top > 0 && tmp_path[top - 1] == '/' && cnt == 1 ) 46 { 47 ++index; 48 } 49 // Case 2: copy two dots. 50 else if ( cnt == 2 ) 51 { 52 index -= cnt; 53 } 54 // Case 3: if more than two dots, it is error. 55 else if ( cnt > 2 ) 56 { 57 fprintf( stderr, "Error.\n" ); 58 // Remember: after free memory, this function could leave. 59 free( tmp_path ), tmp_path = NULL; 60 free( result ), result = NULL; 61 return NULL; 62 } 63 64 // copy other characters. 65 while ( index < len && path[index] != '/' ) 66 { 67 tmp_path[top++] = path[index++]; 68 } 69 } 70 71 // other operators. 72 tmp_path[top] = '\0'; 73 len = top; 74 for ( index = 0, top = 0; index < len; ) 75 { 76 // copy other characters except '.' 77 while ( index < len && tmp_path[index] != '.' ) 78 { 79 result[top++] = tmp_path[index++]; 80 } 81 82 // count of point 83 for ( cnt = 0; index < len && tmp_path[index] == '.'; ++index, ++cnt ); 84 85 // Case 1: the number of '.' is 2; 86 if ( top > 0 && cnt == 2 ) 87 { 88 --top; 89 while ( --top > 0 && result[top] != '/' ); 90 } 91 // Case 2: "game.gif" 92 else if ( top > 0 && result[top - 1] != '/' && cnt == 1 ) 93 { 94 result[top++] = '.'; 95 } 96 // Case 3: "/../../../" -> "/" 97 else if ( top == 0) 98 { 99 ++top; 100 } 101 102 } 103 result[top] = '\0'; 104 105 // free memory 106 free( tmp_path ), tmp_path = NULL; 107 108 return result; 109 } 110 111 void output( const char *path ) 112 { 113 char *result = NULL; 114 115 result = normalize_path( path ); 116 printf( "Original is %s\nResult is %s\n\n", path, result ); 117 free( result ), result = NULL; 118 119 free( result ); 120 result = NULL; 121 } 122 123 int main() 124 { 125 char *path1 = "/home/news/./../tmp/game/../"; 126 char *path2 = "/../../../abc"; 127 char *path3 = "/game/gif.big"; 128 char *path4 = "///abc//..//edf/game.f"; 129 130 output( path1 ); 131 output( path2 ); 132 output( path3 ); 133 output( path4 ); 134 135 return 0; 136 }