startsWith(str_a, str_b)
표준 C 라이브러리 와 같은 것이 있습니까?
널 바이트로 끝나는 두 문자열에 대한 포인터를 가져 와서 첫 번째 문자열도 두 번째 문자열의 시작 부분에 완전히 나타나는지 여부를 알려줍니다.
예 :
"abc", "abcdef" -> true
"abcdef", "abc" -> false
"abd", "abdcef" -> true
"abc", "abc" -> true
startsWith(str_a, str_b)
표준 C 라이브러리 와 같은 것이 있습니까?
널 바이트로 끝나는 두 문자열에 대한 포인터를 가져 와서 첫 번째 문자열도 두 번째 문자열의 시작 부분에 완전히 나타나는지 여부를 알려줍니다.
예 :
"abc", "abcdef" -> true
"abcdef", "abc" -> false
"abd", "abdcef" -> true
"abc", "abc" -> true
답변:
분명히 이것에 대한 표준 C 기능이 없습니다. 그래서:
bool startsWith(const char *pre, const char *str)
{
size_t lenpre = strlen(pre),
lenstr = strlen(str);
return lenstr < lenpre ? false : memcmp(pre, str, lenpre) == 0;
}
위의 내용은 훌륭하고 명확하지만 꽉 끼거나 매우 큰 문자열로 작업 하는 경우 두 문자열의 전체 길이를 앞에서 스캔하므로 최상의 성능을 제공하지 못합니다 ( strlen
). wj32 또는 Christoph 와 같은 솔루션 은 더 나은 성능을 제공 할 수 있습니다 (하지만 벡터화에 대한 이 설명 은 C의 범위를 벗어납니다). 또한주의 프레드 푸의 솔루션 피 strlen
에를 str
(당신이 사용하는 경우 그 오른쪽이 불필요 것 strncmp
대신에 memcmp
). (매우) 큰 문자열이나 타이트한 루프에서 반복적으로 사용하는 경우에만 중요하지만 중요한 경우에는 중요합니다.
memcmp
을 위해 strncmp
여기가 빠릅니다. 두 문자열 모두 최소 lenpre
바이트 가있는 것으로 알려져 있기 때문에 UB가 없습니다 . strncmp
NUL에 대해 두 문자열의 각 바이트를 확인하지만 strlen
호출은 이미 없음을 보장합니다. (하지만 여전히 성능은 당신이 언급 한, 때 충돌했다고 pre
또는 str
이상 실제 일반적인 초기 시퀀스보다.)
memcmp
위의 사용 은 여기에서 다른 답변에서 적절하지 않기 때문에 계속해서 답변에서 변경했습니다.
strlen
그리고 memcmp
매우 빠른 하드웨어 지침 구현 될 수 있으며, strlen
s는 더블 메모리 히트를 피하기 위해, 캐시로 문자열을 넣을 수 있습니다. 이러한 시스템에서는 strncmp
두 개의 strlen
s 및 memcmp
이와 같이 구현 될 수 있지만 짧은 공통 접두사가있는 긴 문자열에서 훨씬 더 오래 걸릴 수 있으므로 라이브러리 작성자가 그렇게하는 것은 위험 할 수 있습니다. 여기서 히트는 명시 적이며 strlen
s는 각각 한 번만 수행됩니다 (Fred Foo 's strlen
+ strncmp
는 3을 수행합니다).
이에 대한 표준 기능은 없지만 정의 할 수 있습니다.
bool prefix(const char *pre, const char *str)
{
return strncmp(pre, str, strlen(pre)) == 0;
}
C 표준 (7.21.4.4/2)에 따라 str
짧아지는 것에 대해 걱정할 필요가 없습니다 pre
.
이
strncmp
함수는n
에서 가리키는 배열에서에서 가리키는 배열까지의 문자 (널 문자 뒤에 오는 문자는 비교되지 않음) 이하를 비교s1
합니다s2
. "
strncmp
입니다.
strncmp
및 strlen
"strncmp 소위"되지 않습니다.
나는 아마 함께 갈 strncmp()
것이지만 재미를 위해 원시 구현을 :
_Bool starts_with(const char *restrict string, const char *restrict prefix)
{
while(*prefix)
{
if(*prefix++ != *string++)
return 0;
}
return 1;
}
strncmp
컴파일러는 벡터화 잘 정말하지 않는 glibc는 작가가 확인 :-) 때문에,
strstr()
기능을 사용하십시오 . Stra == strstr(stra, strb)
최적화 됨 (v.2.-수정 됨) :
uint32 startsWith( const void* prefix_, const void* str_ ) {
uint8 _cp, _cs;
const uint8* _pr = (uint8*) prefix_;
const uint8* _str = (uint8*) str_;
while ( ( _cs = *_str++ ) & ( _cp = *_pr++ ) ) {
if ( _cp != _cs ) return 0;
}
return !_cp;
}
startsWith("\2", "\1")
1 반환, startsWith("\1", "\1")
또한 1 반환
허용 된 버전을 실행하고 매우 긴 str에 문제가 있었기 때문에 다음 논리를 추가해야했습니다.
bool longEnough(const char *str, int min_length) {
int length = 0;
while (str[length] && length < min_length)
length++;
if (length == min_length)
return true;
return false;
}
bool startsWith(const char *pre, const char *str) {
size_t lenpre = strlen(pre);
return longEnough(str, lenpre) ? strncmp(str, pre, lenpre) == 0 : false;
}
또는 두 가지 접근 방식의 조합 :
_Bool starts_with(const char *restrict string, const char *restrict prefix)
{
char * const restrict prefix_end = prefix + 13;
while (1)
{
if ( 0 == *prefix )
return 1;
if ( *prefix++ != *string++)
return 0;
if ( prefix_end <= prefix )
return 0 == strncmp(prefix, string, strlen(prefix));
}
}
편집 : strncmp가 0을 반환하면 종료 0 또는 길이 (block_size)에 도달했는지 알 수 없기 때문에 아래 코드가 작동 하지 않습니다 .
추가 아이디어는 블록 단위로 비교하는 것입니다. 블록이 같지 않으면 해당 블록을 원래 함수와 비교하십시오.
_Bool starts_with_big(const char *restrict string, const char *restrict prefix)
{
size_t block_size = 64;
while (1)
{
if ( 0 != strncmp( string, prefix, block_size ) )
return starts_with( string, prefix);
string += block_size;
prefix += block_size;
if ( block_size < 4096 )
block_size *= 2;
}
}
상수는 13
, 64
, 4096
,의뿐만 아니라 지수는 block_size
단지 추측이다. 사용 된 입력 데이터 및 하드웨어에 대해 선택해야합니다.
block_size
증가는 포인터 증가 이후 여야합니다. 이제 수정되었습니다.