这是一个简单的文件路径plain-C例程,它应该以编程方式扩展tildes并接受空格作为文件名中的合法字符。它适用于以下名称:
〜/ Test Folder / test.txt
/ Users / Shared / Test Folder / test.txt
但似乎不适用于Apple建议的路径语法或Terminal.app生成的路径语法,如果将文件的图标拖放到Terminal.app的窗口:
/ Users / Shared / Test \ Folder / test.txt
或
〜/ Test \ Folder / test.txt
这是代码。我显然错过了将“转义的空白”替换为“普通空白”字符的例程。另一方面,'\'的任何搜索例程都会导致编译器抱怨“未知转义序列”0x20(在某些unix和linux系统中,btw似乎是有效的空白代码,可能不在OSX中?)。
在普通C和C字符串中是否有解决问题的方法,而不必处理Apple的专有CFStrings和NSStrings,我知道解决方案很简单?我只是负担不起使用这个程序中的任何一个。也没有shell脚本,ruby,gawk,grep,perl,python等...,请。
提前致谢!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wordexp.h>
void get_file_path(char path[])
{
char *p;
size_t len = 0;
wordexp_t exp_result;
printf("Enter file name: \n");
p = fgets(path, TEXT_SIZE, stdin);
fflush(stdin);
if(p != NULL)len = strlen(path);
//get rid of newline characters
for(p = path; p < path + len; p++){
if(*p == '\n') *p = '\0';
}
if(path[0] == '~'){
wordexp(path, &exp_result, 0);
//printf("Num.expansions: %zd\n", exp_result.we_wordc);
strcpy(path, exp_result.we_wordv[0]);
for(size_t i = 1; i < exp_result.we_wordc; i++){
//printf("%s\n", exp_result.we_wordv[i]);
strcat(path, " ");
strcat(path, exp_result.we_wordv[i]);
}
wordfree(&exp_result);
}
printf("File path: %s\n", path);
return;
}
这是shell输出:
Enter file name:
/Users/Shared/Test\ Folder/test.txt
File path: /Users/Shared/Test\ Folder/test.txt
Can't open file: /Users/Shared/Test\ Folder/test.txt
答案 0 :(得分:1)
iharob是正确的,shell会将"\ "
的未引用或双引号(&#34; ...&#34;)外观转换为单个空格字符。结果空间不会分割单词。另一方面,只有当您首先将这样的字符串呈现给shell时才会发生这种情况。如果绕过shell,则不会发生这种情况,例如,当您通过exec()
函数系列直接启动进程时,或者仅在程序内部使用该字符串时。
您似乎在区分shell语法和C语法方面遇到了一些麻烦。 shell将反斜杠字符解释为通用转义字符,但C只识别特定的转义序列(全部由反斜杠引入),而'\ '
不是其中之一。
另一方面,'\\'
是其中之一:它代表一个反斜杠字符。因此,如果您要查找两个字符的字符串,其元素是反斜杠后跟空格,那么在C中拼写为"\\ "
。
<强>更新强>
除此之外,我认为您的真正问题是,只有当字符串的第一个字符是~
时,您的程序才会执行扩展。在您提供的测试运行中情况并非如此。如果无条件地执行扩展,那么您的代码(或多或少)对我有用。
答案 1 :(得分:1)
这个稍微修改过的代码似乎可以完成这项工作。这是一个非常简单的解决方案,它将除了文字反斜杠(\)之外的所有字符复制到辅助字符数组,并在搜索数组开头的波浪线(〜)之前调整此数组的长度,并在路径找到波形符的情况下展开路径。感谢您的讨论,解释,建议和评论!
bool get_file_path(char path[]){
char *p, *p1;
char path1[TEXT_SIZE];
size_t len = 0;
size_t len1, i;
wordexp_t exp_result;
printf("Enter file name: \n");
fix:
p = fgets(path, TEXT_SIZE, stdin);
if(p == NULL) return false;
else{
len = strlen(path);
if(strcmp(path,"\n") == 0)goto fix;
}
//get rid of "escaped whitespaces"
for(p = path, p1 = path1, len1 = len; p < path + len; p++, p1++){
if(*p == '\\'){p++; len1--;}
*p1 = *p;
}
//get rid of newline characters
for(p1 = path1; p1 < path1 + len1; p1++){
if(*p1 == '\n') *p1 = '\0';
}
if(path1[0] == '~'){
wordexp(path1, &exp_result, 0);
//printf("Num.expansions: %zd\n", exp_result.we_wordc);
strcpy(path1, exp_result.we_wordv[0]);
for(i = 1; i < exp_result.we_wordc; i++){
//printf("%s\n", exp_result.we_wordv[i]);
strcat(path1, " ");
strcat(path1, exp_result.we_wordv[i]);
}
wordfree(&exp_result);
}
strcpy(path, path1);
printf("File path: %s\n", path);
return true;
}
<强>更新强>
由于 fflush(stdin)会生成除Linux之外的未定义行为,因此额外的三行代码可以帮助摆脱 stdin 缓冲区中的“杂散换行符”而不是依赖在 fflush()上做。
答案 2 :(得分:0)
这不是代码主要问题的答案,但它是代码的问题。
if(path[0] == '~'){
是一个微妙的问题。
p = fgets(path, TEXT_SIZE, stdin);
...
if(path[0] == '~'){
p == NULL
{IO}错误时未定义path
的内容,EOF
发生时可能是之前的缓冲区内容。最好将返回类型从void
更改为char *
,并在p == NULL
时返回。
p = fgets(path, TEXT_SIZE, stdin);
if (p == NULL) {
return NULL;
}