路径 osx/unix/darwin 中的转义空格,纯 C
escaped whitespaces in paths osx/unix/darwin, plain C
这是一个简单的文件路径纯 C 例程,它应该以编程方式扩展波浪号并接受空格作为文件名中的合法字符。它适用于以下名称:
~/测试Folder/test.txt
/Users/Shared/Test Folder/test.txt
但如果将文件图标拖放到 Terminal.app 的 window:
/Users/Shared/Test\Folder/test.txt
或
~/测试\Folder/test.txt
这是代码。我显然错过了将 'escaped whitespace' 替换为 'plain whitespace' 字符的例程。另一方面,“\”的任何搜索例程都会导致编译器抱怨 "unknown escape sequence" 0x20(顺便说一句,这似乎是某些 unix 和 linux 系统中的有效空白代码,可能不在 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 = '[=11=]';
}
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
iharob 是正确的,shell 会将出现的 "\ "
的未加引号或双引号(“...”)翻译成单个 space 字符。结果 space 不拆分单词。另一方面,只有当您首先将这样的字符串呈现给 shell 时才会发生这种情况。如果您绕过 shell,则不会发生这种情况,例如当您直接通过 exec()
系列函数启动进程时,或者当字符串仅在程序内部使用时。
您似乎在区分 shell 语法和 C 语法时遇到了一些麻烦。 shell 将反斜杠字符解释为 通用 转义字符,但 C 仅识别特定的转义序列(全部由反斜杠引入)而 '\ '
不是一个其中
另一方面,'\'
是其中之一:它表示单个反斜杠字符。因此,如果您正在寻找一个双字符字符串的字符串文字,其元素是反斜杠后跟 space,那么在 C 中拼写为 "\ "
.
更新:
除此之外,我认为您的真正问题是您的程序仅在字符串的第一个字符是 ~
时才执行扩展。在您提供的测试 运行 中情况并非如此。如果扩展是无条件执行的,那么你的代码(或多或少)对我有用。
这个稍微修改过的代码似乎可以完成这项工作。这是一个非常简单的解决方案,它将除文字反斜杠 ( \ ) 之外的所有字符复制到辅助字符数组,并在搜索波浪号 (~) 之前调整该数组的长度,然后在数组的开头搜索波浪号 (~) 并扩展路径以防在那里找到波浪号.感谢大家的讨论、解释、建议和意见!
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 = '[=10=]';
}
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 之外的未定义行为,三行额外的代码可以帮助摆脱 "stray newlines" 中的 [=] 17=]stdin 缓冲区而不是依赖 fflush() 来做。
这不是代码主要问题的答案,但它是代码的问题。
if(path[0] == '~'){
是一个微妙的问题。
p = fgets(path, TEXT_SIZE, stdin);
...
if(path[0] == '~'){
当 p == NULL
时,path
的内容未定义 IO 错误,并且很可能是 EOF
时的先前缓冲区内容。最好将 return 类型从 void
更改为 char *
,当 p == NULL
时 return。
p = fgets(path, TEXT_SIZE, stdin);
if (p == NULL) {
return NULL;
}
这是一个简单的文件路径纯 C 例程,它应该以编程方式扩展波浪号并接受空格作为文件名中的合法字符。它适用于以下名称:
~/测试Folder/test.txt
/Users/Shared/Test Folder/test.txt
但如果将文件图标拖放到 Terminal.app 的 window:
/Users/Shared/Test\Folder/test.txt
或
~/测试\Folder/test.txt
这是代码。我显然错过了将 'escaped whitespace' 替换为 'plain whitespace' 字符的例程。另一方面,“\”的任何搜索例程都会导致编译器抱怨 "unknown escape sequence" 0x20(顺便说一句,这似乎是某些 unix 和 linux 系统中的有效空白代码,可能不在 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 = '[=11=]';
}
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
iharob 是正确的,shell 会将出现的 "\ "
的未加引号或双引号(“...”)翻译成单个 space 字符。结果 space 不拆分单词。另一方面,只有当您首先将这样的字符串呈现给 shell 时才会发生这种情况。如果您绕过 shell,则不会发生这种情况,例如当您直接通过 exec()
系列函数启动进程时,或者当字符串仅在程序内部使用时。
您似乎在区分 shell 语法和 C 语法时遇到了一些麻烦。 shell 将反斜杠字符解释为 通用 转义字符,但 C 仅识别特定的转义序列(全部由反斜杠引入)而 '\ '
不是一个其中
另一方面,'\'
是其中之一:它表示单个反斜杠字符。因此,如果您正在寻找一个双字符字符串的字符串文字,其元素是反斜杠后跟 space,那么在 C 中拼写为 "\ "
.
更新:
除此之外,我认为您的真正问题是您的程序仅在字符串的第一个字符是 ~
时才执行扩展。在您提供的测试 运行 中情况并非如此。如果扩展是无条件执行的,那么你的代码(或多或少)对我有用。
这个稍微修改过的代码似乎可以完成这项工作。这是一个非常简单的解决方案,它将除文字反斜杠 ( \ ) 之外的所有字符复制到辅助字符数组,并在搜索波浪号 (~) 之前调整该数组的长度,然后在数组的开头搜索波浪号 (~) 并扩展路径以防在那里找到波浪号.感谢大家的讨论、解释、建议和意见!
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 = '[=10=]';
}
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 之外的未定义行为,三行额外的代码可以帮助摆脱 "stray newlines" 中的 [=] 17=]stdin 缓冲区而不是依赖 fflush() 来做。
这不是代码主要问题的答案,但它是代码的问题。
if(path[0] == '~'){
是一个微妙的问题。
p = fgets(path, TEXT_SIZE, stdin);
...
if(path[0] == '~'){
当 p == NULL
时,path
的内容未定义 IO 错误,并且很可能是 EOF
时的先前缓冲区内容。最好将 return 类型从 void
更改为 char *
,当 p == NULL
时 return。
p = fgets(path, TEXT_SIZE, stdin);
if (p == NULL) {
return NULL;
}