Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 从字符串中提取字符串值_C - Fatal编程技术网

C 从字符串中提取字符串值

C 从字符串中提取字符串值,c,C,通用条款4.4.3 c89 我有以下字符串 sip:12387654345443222118765@xxx.xxx.xxx.xxx 我怎样才能只提取数字?我只想知道电话号码 12387654345443222118765 非常感谢您的建议,听起来您希望它是一个数字类型,这将很困难(它太大,无法容纳int或long)。理论上,你可以这样做: const char* original = "sip:12387654345443222118765@xxx.xxx.xxx.xxx"; long nu

通用条款4.4.3 c89

我有以下字符串

sip:12387654345443222118765@xxx.xxx.xxx.xxx
我怎样才能只提取数字?我只想知道电话号码

12387654345443222118765

非常感谢您的建议,

听起来您希望它是一个数字类型,这将很困难(它太大,无法容纳int或long)。理论上,你可以这样做:

const char* original = "sip:12387654345443222118765@xxx.xxx.xxx.xxx";
long num = strtoul(original + 4, NULL, 10);
但是它将溢出并且
strtoul
将返回-1。如果您希望它作为一个字符串,并且您知道它总是精确的长度,那么您可以使用
strcpy
/
strncpy
拉出子字符串:

const char* original = "sip:12387654345443222118765@xxx.xxx.xxx.xxx";
char num[24];
strncpy(num, original + 4, 23);
num[23] = 0;
如果您不知道每次将有23个字符长,则需要首先在原始字符串中找到@符号:

unsigned int num_length = strchr(original, '@') - (original + 4);
char* num = malloc(num_length + 1);
strncpy(num, original + 4, num_length);
num[num_length] = 0;

查看strtok或strtok_r函数。

使用正则表达式:)

#包括
regcomp()//编译您的正则表达式
regexec()//运行您的正则表达式
regfree()//释放您的正则表达式

:)

下面是另一种查找连续数字序列的方法:

char *start = sipStr + strcspn(sipStr, "0123456789");
int len = strspn(start, "0123456789");

char *copy = malloc(len + 1);

memcpy(copy, start, len);
copy[len] = '\0'; //add null terminator

...
//don't forget to
free(copy);

下面是一些处理可变宽度子字符串的内容,它不关心子字符串的起始位置。例如,如果字符串是
iax2:xxx@xx.xx.xx.xx
,它仍然可以工作。但是,如果找不到任何一个分隔符,它将返回NULL

它使用
strchr()
查找分隔符,让我们知道从哪里开始复制,从哪里停止复制。它返回一个分配的字符串,调用函数必须
free()
返回的指针

我很确定这就是你想要的

注意:从原始版本进行编辑,以使其更易于重复使用和更理智。

#include <stdio.h>                                                                              
#include <string.h>
#include <stdlib.h>

char *extract_string(const char *str, const char s1, const char s2)
{
    char *ret = NULL, *pos1 = NULL, *pos2 = NULL;
    size_t len;

    if (str == NULL || s1 < 0 || s2 < 0)
        return NULL;

    pos1 = strchr(str, s1);
    pos2 = strchr(str, s2);
    if (! pos1 || ! pos2)
        return NULL;

    len = ((pos2 - str) - (pos1 - str) - 1);
    ret = (char *) malloc(len + 1);
    if (ret == NULL)
        return NULL;

    memcpy(ret, str + (pos1 - str) + 1, len);
    ret[len] = '\0';

    return ret;
}

int main(void)
{
    const char *string = "sip:12387654345443222118765@xxx.xxx.xxx.xxx";
    char *buff = NULL;

    buff = extract_string(string, ':', '@');
    if (buff == NULL)
        return 1;

    printf("The string extracted from %s is %s\n" , string, buff);

    free(buff);

    return 0;
}
#包括
#包括
#包括
字符*提取字符串(常量字符*字符串,常量字符s1,常量字符s2)
{
char*ret=NULL,*pos1=NULL,*pos2=NULL;
尺寸透镜;
如果(str==NULL | | s1<0 | | s2<0)
返回NULL;
pos1=strchr(str,s1);
pos2=strchr(str,s2);
如果(!pos1 | |!pos2)
返回NULL;
len=((pos2-str)-(pos1-str)-1);
ret=(char*)malloc(len+1);
if(ret==NULL)
返回NULL;
memcpy(ret,str+(pos1-str)+1,len);
ret[len]='\0';
返回ret;
}
内部主(空)
{
const char*string=“sip:12387654345443222118765@xxx.xxx.xxx.xxx";
char*buff=NULL;
buff=提取字符串(字符串“:”,“@”);
如果(buff==NULL)
返回1;
printf(“从%s提取的字符串是%s\n”,字符串,buff);
免费(buff);
返回0;
}

您可以轻松地修改它,使其不在乎是否找到第二个分隔符,只需将所有内容复制到第一个分隔符的右侧即可。这是读者的练习。

从技术上讲是正确的,但对于这样一个简单的字符串来说,这可能太过分了manipulation@Michael,1)当你维护你的软件时,你会看到它有多好,尤其是在你编写软件6个月后。或者如果需求发生变化。代码需要可读性。2) 您可以制作一个小函数来抽象它,使用两个字符串(一个正则表达式,一个字符串输入,并返回一个带有第一个匹配参数的字符串…),这样您就可以在整个项目中重用它?如果您的需求可能会发生变化,C从一开始就不可能是正确的实现语言。@Artelius我完全不同意!!这取决于你想完成什么。@Pafy Good point;正则表达式以其可维护性和易于读取而闻名。数字的宽度总是可变的。搜索@的最佳方式是什么?谢谢。我只需要使用strchr()来查找“:”,然后再查找“@”,它确切地告诉您应该复制哪些字节(以及返回字符串的长度)。如果起始偏移量不是四个字节,这就避免了任何中断。@Tim是的,这就是我不喜欢字符串解析问题的原因;从一个例子中永远不清楚格式是什么。听起来字符串总是以“sip:”开头,但我不确定它总是以sip:”开头。非常感谢您的解决方案。@Michael-我想不起来我总喜欢用C解析字符串:)您在问题中没有特别要求,这就是为什么我还提到了strtok_r,它也是POSIX,如果您有这个要求,应该这样做。我认为strtok_r()有点过分了。他不需要标记字符串,他只需要提取一个子字符串。嗯,我想是口味的问题。从他给出的例子来看,不清楚这个字符串的开头是否总是相同的长度。例如,可能会出现不同的前缀。我提出了strtok_r解决方案,在两个边界字符之间找到一个字符串,即“:”和“@”。
#include <stdio.h>                                                                              
#include <string.h>
#include <stdlib.h>

char *extract_string(const char *str, const char s1, const char s2)
{
    char *ret = NULL, *pos1 = NULL, *pos2 = NULL;
    size_t len;

    if (str == NULL || s1 < 0 || s2 < 0)
        return NULL;

    pos1 = strchr(str, s1);
    pos2 = strchr(str, s2);
    if (! pos1 || ! pos2)
        return NULL;

    len = ((pos2 - str) - (pos1 - str) - 1);
    ret = (char *) malloc(len + 1);
    if (ret == NULL)
        return NULL;

    memcpy(ret, str + (pos1 - str) + 1, len);
    ret[len] = '\0';

    return ret;
}

int main(void)
{
    const char *string = "sip:12387654345443222118765@xxx.xxx.xxx.xxx";
    char *buff = NULL;

    buff = extract_string(string, ':', '@');
    if (buff == NULL)
        return 1;

    printf("The string extracted from %s is %s\n" , string, buff);

    free(buff);

    return 0;
}