在 c 中提取 "valid" 子字符串的快速方法
quick way to extract "valid" substring in c
我写了两个函数来从一个字符串中提取一个“有效”的子串,这意味着该子串只能包含字母和数字。但是,如果要检查的字符串很长,即使性能差距不太明显,它们也会开始失去性能,我对此并不太兴奋。有没有更快的方法来“验证”字符串?这是我的代码:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <wchar.h>
wchar_t* validstr(wchar_t* src, wchar_t* cc, unsigned int* index) {
wchar_t* valid = calloc(1, sizeof(wchar_t));
while (isalpha(*cc) || isdigit(*cc)) {
valid = realloc(valid, (wcslen(valid) + 2) * sizeof(wchar_t));
wcscat(valid, (wchar_t[]) { *cc, 0 });
++* index;
*cc = src[*index];
}
return valid;
}
wchar_t* validstr2(wchar_t* src) {
wchar_t* valid = calloc(1, sizeof(wchar_t));
while (isalpha(*src) || isdigit(*src)) {
valid = realloc(valid, (wcslen(valid) + 2) * sizeof(wchar_t));
wcscat(valid, (wchar_t[]) { *src, 0 });
src++;
}
return valid;
}
int main() {
wchar_t* str = L"valid10+(notvalidanymore";
// usage for validstr()
wchar_t current = str[0];
unsigned int index = 0;
printf("%ls\n", validstr(str, ¤t, &index));
// usage for validstr2()
printf("%ls\n", validstr2(str));
}
您应尽可能避免重新分配。
所以您可以先数一下与您相关的字符:
size_t length = 0
for(wchar_t* tmp = cc; *tmp && iswalnum(*tmp); ++tmp)
{
++length
}
请注意,isalnum
函数涵盖字母和数字 – 但无论如何您都应该使用宽字符函数(isw[...]
,请注意附加的 w
)。
计算完后,您只需复制感兴趣的值即可:
wchar_t* valid = malloc((length + 1) * sizeof(wchar_t));
// ^ terminating null character!
memcpy(valid, cc, length*sizeof(wchar_t));
valid[length] = 0;
// for validstr:
memcpy(cc, src, length*sizeof(wchar_t));
*index = length;
相比calloc
,我更喜欢这里的malloc
,因为不需要对数组进行零初始化,无论如何它都会被覆盖。
请注意,validstr
的上述版本与您的实现略有不同:您 先递增,然后复制字符,这会跳过 [=19 的第一个字符=].我的版本从第一个字符开始复制。如果跳过第一个字符实际上是有意的,那么从第一个字符开始复制你就可以了:
memcpy(cc, src + 1, length);
请注意,这个版本 (validstr(wchar_t*, wchar_t*, unsigned int*)
) 无论如何对我来说都不是很安全,您可能很容易读取超出 src 范围的内容,这将导致未定义的行为——除非您始终以任何方式保证src
至少与复制的子字符串一样长。
我写了两个函数来从一个字符串中提取一个“有效”的子串,这意味着该子串只能包含字母和数字。但是,如果要检查的字符串很长,即使性能差距不太明显,它们也会开始失去性能,我对此并不太兴奋。有没有更快的方法来“验证”字符串?这是我的代码:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <wchar.h>
wchar_t* validstr(wchar_t* src, wchar_t* cc, unsigned int* index) {
wchar_t* valid = calloc(1, sizeof(wchar_t));
while (isalpha(*cc) || isdigit(*cc)) {
valid = realloc(valid, (wcslen(valid) + 2) * sizeof(wchar_t));
wcscat(valid, (wchar_t[]) { *cc, 0 });
++* index;
*cc = src[*index];
}
return valid;
}
wchar_t* validstr2(wchar_t* src) {
wchar_t* valid = calloc(1, sizeof(wchar_t));
while (isalpha(*src) || isdigit(*src)) {
valid = realloc(valid, (wcslen(valid) + 2) * sizeof(wchar_t));
wcscat(valid, (wchar_t[]) { *src, 0 });
src++;
}
return valid;
}
int main() {
wchar_t* str = L"valid10+(notvalidanymore";
// usage for validstr()
wchar_t current = str[0];
unsigned int index = 0;
printf("%ls\n", validstr(str, ¤t, &index));
// usage for validstr2()
printf("%ls\n", validstr2(str));
}
您应尽可能避免重新分配。
所以您可以先数一下与您相关的字符:
size_t length = 0
for(wchar_t* tmp = cc; *tmp && iswalnum(*tmp); ++tmp)
{
++length
}
请注意,isalnum
函数涵盖字母和数字 – 但无论如何您都应该使用宽字符函数(isw[...]
,请注意附加的 w
)。
计算完后,您只需复制感兴趣的值即可:
wchar_t* valid = malloc((length + 1) * sizeof(wchar_t));
// ^ terminating null character!
memcpy(valid, cc, length*sizeof(wchar_t));
valid[length] = 0;
// for validstr:
memcpy(cc, src, length*sizeof(wchar_t));
*index = length;
相比calloc
,我更喜欢这里的malloc
,因为不需要对数组进行零初始化,无论如何它都会被覆盖。
请注意,validstr
的上述版本与您的实现略有不同:您 先递增,然后复制字符,这会跳过 [=19 的第一个字符=].我的版本从第一个字符开始复制。如果跳过第一个字符实际上是有意的,那么从第一个字符开始复制你就可以了:
memcpy(cc, src + 1, length);
请注意,这个版本 (validstr(wchar_t*, wchar_t*, unsigned int*)
) 无论如何对我来说都不是很安全,您可能很容易读取超出 src 范围的内容,这将导致未定义的行为——除非您始终以任何方式保证src
至少与复制的子字符串一样长。