【问题标题】:How To Write *nix's basename in C如何在 C 中编写 *nix 的基本名称
【发布时间】:2012-05-16 06:44:57
【问题描述】:

我想从字符串中提取基本名称,例如

/opt/home/etc/sample

即我要解析返回sample的大长度字符串,或者子字符串 在最后一个 / 字符之后。字符串可以是任意长度。

这是怎么做到的?

【问题讨论】:

  • 使用strrpos()substr() 实现。
  • @alex,这些是 C++ 函数。 C 有strrchr
  • @ugoren 我忘记了很多 C。你总是可以在 C 中实现它们 :)

标签: c substring


【解决方案1】:
char *input = "/opt/home/etc/sample";
char *output = NULL;

output = strrchr(input, '/');

if(output != NULL)
{
    printf("%s\n", output);
}

或者其他方式是你可以尝试自己解析(下面的代码只是一个示例,并没有处理所有的错误和边界条件,你可以自己尝试和学习)

char *input = "/opt/home/etc/sample";
int len = 0;
char *temp = NULL;

len = strlen(input);
temp = input + (len-1);
len--;

while((*temp != '/') && (len >= 0))
{
  temp--;
  len--;
}


if(len>=0)
{
   printf("%s\n", temp);
}

【讨论】:

    【解决方案2】:

    你可以使用 strtok_r

    #include <stdio.h>
    #include <string.h>
    
    int main ()
    {
      char str[] ="This/a/sample/string";
      char * pch;
      char * ans;
      printf ("Splitting string \"%s\" into tokens:\n",str);
      pch = strtok_r (str,"/");
      if(pch==NULL)
      ans = str;
      while (pch != NULL)
      {
        ans = pch;
        pch = strtok_r (NULL, "/");
      }
      return 0;
    }
    

    P.S 请检查代码是否有一些小错误

    【讨论】:

    • 谢谢 nischayn22。 strtok 给了我预期的输出。
    • -1: not thread-safe/reentrant + 如果str 不包含/,则会严重失败。
    • @PaulR 感谢您指出这一点,您能解释一下线程安全部分吗?
    • strtok 不可重入 - 请参阅手册页 - 使用 strtok_r
    • 另请注意您的最新编辑 - 您不能只检查ans == NULL,因为它没有初始化,如果str 不包含/,它将是未定义的。请注意,为了匹配 basename 的行为,如果没有路径分隔符,您应该返回整个字符串。
    【解决方案3】:

    在 POSIX 中有 basename / dirname 函数。它们的返回值将指向静态内存或输入的某些后缀,因此无需释放它。这可能比自己拆分字符串更容易:

      // assuming you own *path:
      char *file = basename(path);
      char *dir = dirname(path);   //that's all!
    

    path".""..""foo/" 时,它们还处理特殊情况(那么,基本名称为"." - 正确)。

    但请注意,如果您不拥有该字符串:它们采用非常量参数,并且可能会修改它。

    如果你真的需要在const char *上使用basename,解决方法差不多

      #include <libgen.h>  // POSIX
    
      void die(const char * errormessage);
    
      /* version of basename(3) that does not modify its argument.
       * This assumes that "path" is correctly 0-terminated!
       * Please free() the return value after use. */
      char * basename_safe(const char * path)
      {
        char * result;
        char * what_basename_says;
    
        if (!path) {
          // return a pointer to ".":
          result = malloc(2 * sizeof(char));
          if (!result) die("malloc failed!");
          result[0] = '.';
          result[1] = 0;
          return result;
        }
    
        // in case path is the empty string, we need 2 chars to store the result ".",
        // so add 2:
        result = malloc((2 + strlen(path)) * sizeof(char));
        if (!result) die("malloc failed");
    
        // basename wants write access to its argument:
        strcpy(result, path);
    
        what_basename_says = basename(result);
        // now what_basename_says actually may be a pointer into *result.
    
        strcpy(result, what_basename_says);
        // to allow for free(result)
    
        return result;
      }
    

    但是,就像我之前说的:如果你知道你可以修改*path,那么你还不如使用basename而不用这些。

    【讨论】:

    • strcpy(result, what_basename_says);:正如你所说,what_basename_says 可能是指向*result 的指针。当s1s2 重叠时,strcpy(s1, s2) 的行为是未定义
    猜你喜欢
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多