문자열이 C에서 다른 문자열로 시작하는지 확인하는 방법은 무엇입니까?


85

startsWith(str_a, str_b)표준 C 라이브러리 와 같은 것이 있습니까?

널 바이트로 끝나는 두 문자열에 대한 포인터를 가져 와서 첫 번째 문자열도 두 번째 문자열의 시작 부분에 완전히 나타나는지 여부를 알려줍니다.

예 :


3
세 번째 예가 진정한 결과를 가져야한다고 생각합니다.
Michael Burr 2011 년

답변:


76

분명히 이것에 대한 표준 C 기능이 없습니다. 그래서:


위의 내용은 훌륭하고 명확하지만 꽉 끼거나 매우 큰 문자열로 작업 하는 경우 두 문자열의 전체 길이를 앞에서 스캔하므로 최상의 성능을 제공하지 못합니다 ( strlen). wj32 또는 Christoph 와 같은 솔루션 은 더 나은 성능을 제공 할 수 있습니다 (하지만 벡터화에 대한 이 설명 은 C의 범위를 벗어납니다). 또한주의 프레드 푸의 솔루션strlen에를 str(당신이 사용하는 경우 그 오른쪽이 불필요 것 strncmp대신에 memcmp). (매우) 큰 문자열이나 타이트한 루프에서 반복적으로 사용하는 경우에만 중요하지만 중요한 경우에는 중요합니다.


5
내가 언급해야 일반적인 문자열이 첫 번째 매개 변수가 될하는 일이 될 것이다, 그리고 수 초에 접두사. 그러나 나는 당신의 질문이 어떻게 짜여진 것처럼 보였기 때문에 위와 같이 보관했습니다 ... 순서는 전적으로 당신에게 달려 있지만 실제로는 다른 방식으로해야했습니다. 대부분의 문자열 함수는 전체 문자열을 첫 번째 인수, 두 번째로 하위 문자열.
TJ Crowder

1
이것은 우아한 솔루션이지만 성능 문제가 있습니다. 최적화 된 구현은 각 문자열에서 min (strlen (pre), strlen (str)) 이상의 문자를 보지 않으며 첫 번째 불일치 이상을 보지 않습니다. 현이 길지만 초기 불일치가 흔하다면 매우 가볍습니다. 그러나이 구현은 두 문자열의 전체 길이를 앞쪽으로 사용하므로 문자열이 첫 번째 문자에서 다르더라도 최악의 성능을 발휘합니다. 이것이 정말로 중요한지 여부는 상황에 따라 다르지만 잠재적 인 문제입니다.
Tom Karzes

1
당신은 대체 할 수 @TomKarzes memcmp을 위해 strncmp여기가 빠릅니다. 두 문자열 모두 최소 lenpre바이트 가있는 것으로 알려져 있기 때문에 UB가 없습니다 . strncmpNUL에 대해 두 문자열의 각 바이트를 확인하지만 strlen호출은 이미 없음을 보장합니다. (하지만 여전히 성능은 당신이 언급 한, 때 충돌했다고 pre또는 str이상 실제 일반적인 초기 시퀀스보다.)
짐 Balter

1
@JimBalter-아주 좋은 지적입니다! memcmp위의 사용 은 여기에서 다른 답변에서 적절하지 않기 때문에 계속해서 답변에서 변경했습니다.
TJ Crowder

1
PS이 (현재) 일부 문자열 일부 시스템에서 가장 빠른 해답이 될 수 있기 때문에 strlen그리고 memcmp매우 빠른 하드웨어 지침 구현 될 수 있으며, strlens는 더블 메모리 히트를 피하기 위해, 캐시로 문자열을 넣을 수 있습니다. 이러한 시스템에서는 strncmp두 개의 strlens 및 memcmp이와 같이 구현 될 수 있지만 짧은 공통 접두사가있는 긴 문자열에서 훨씬 더 오래 걸릴 수 있으므로 라이브러리 작성자가 그렇게하는 것은 위험 할 수 있습니다. 여기서 히트는 명시 적이며 strlens는 각각 한 번만 수행됩니다 (Fred Foo 's strlen+ strncmp는 3을 수행합니다).
Jim Balter

160

이에 대한 표준 기능은 없지만 정의 할 수 있습니다.

C 표준 (7.21.4.4/2)에 따라 str짧아지는 것에 대해 걱정할 필요가 없습니다 pre.

strncmp함수는 n에서 가리키는 배열에서에서 가리키는 배열까지의 문자 (널 문자 뒤에 오는 문자는 비교되지 않음) 이하를 비교 s1합니다 s2. "


12
대답이 아니오 인 이유는 무엇입니까? 분명히 대답은 '예' strncmp입니다.
Jasper

7
^ 대답이 '아니오'인 이유는 분명합니다. 사용 알고리즘 strncmpstrlen"strncmp 소위"되지 않습니다.
Jim Balter

34

나는 아마 함께 갈 strncmp()것이지만 재미를 위해 원시 구현을 :


6
나는 이것이 가장 마음에 듭니다-길이에 대해 문자열 중 하나를 스캔 할 이유가 없습니다.
마이클 버

1
아마도 strlen + strncmp도 사용할 수 있지만 실제로는 작동하지만 모호한 정의에 대한 모든 논란이 나를 미루고 있습니다. 그래서 이것을 사용하겠습니다. 감사합니다.
Sam Watkins 2015 년

4
이것은보다 느린 될 가능성이 strncmp컴파일러는 벡터화 잘 정말하지 않는 glibc는 작가가 확인 :-) 때문에,
치로 틸리郝海东冠状病六四事件法轮功

3
이 버전은 접두사가 일치하지 않는 경우 strlen + strncmp 버전보다 빠릅니다. 특히 처음 몇 글자에 이미 차이가있는 경우 더욱 그렇습니다.
dpi

1
^ 그 최적화는 함수가 인라인 된 경우에만 적용됩니다.
Jim Balter

5

나는 우아한 코드를 작성하는 데 전문가는 아니지만 ...


5

strstr()기능을 사용하십시오 . Stra == strstr(stra, strb)


3
그것은 다소 거꾸로 보이는 방식으로 보입니다. strb가 접두사인지 아닌지 매우 짧은 초기 세그먼트에서 명확해야하지만 전체 stra를 통과 할 것입니다.
StasM 2011 년

1
조기 최적화는 모든 악의 근원입니다. 시간이 중요한 코드 나 긴 문자열이 아니라면 이것이 최선의 해결책이라고 생각합니다.
Frank Buss

1
@ilw 유명한 컴퓨터 과학자들의 유명한 말입니다-google it. 종종 잘못 적용됩니다 (여기에 있음) ... joshbarczak.com/blog/?p=580
Jim Balter 19

2

최적화 됨 (v.2.-수정 됨) :


2
voting negative : startsWith("\2", "\1")1 반환, startsWith("\1", "\1")또한 1 반환
thejh

이 결정은 instrisincs를 사용하지 않기 때문에 clang에서 최적화를 사용하지 않습니다.
socketpair

^ 내장 함수는 특히 대상 문자열이 접두사보다 훨씬 긴 경우 여기에서 도움이되지 않습니다.
Jim Balter

1

허용 된 버전을 실행하고 매우 긴 str에 문제가 있었기 때문에 다음 논리를 추가해야했습니다.


1

또는 두 가지 접근 방식의 조합 :

편집 : strncmp가 0을 반환하면 종료 0 또는 길이 (block_size)에 도달했는지 알 수 없기 때문에 아래 코드가 작동 하지 않습니다 .

추가 아이디어는 블록 단위로 비교하는 것입니다. 블록이 같지 않으면 해당 블록을 원래 함수와 비교하십시오.

상수는 13, 64, 4096,의뿐만 아니라 지수는 block_size단지 추측이다. 사용 된 입력 데이터 및 하드웨어에 대해 선택해야합니다.


이것들은 좋은 아이디어입니다. 첫 번째 것은 접두사가 12 바이트 (NUL 포함 13 개)보다 짧은 경우 기술적으로 정의되지 않은 동작입니다. 언어 표준은 바로 다음 바이트가 아닌 문자열 외부의 주소를 계산 한 결과를 정의하지 않기 때문입니다.
Jim Balter

@JimBalter : 참조를 추가 할 수 있습니까? 포인터가 역 참조되고 종료 0 이후에 있으면 deferenced 포인터 값이 정의되지 않습니다. 그러나 주소 자체가 정의되지 않은 이유는 무엇입니까? 단지 계산 일뿐입니다.
shpc

그러나 일반적인 버그가있었습니다. block_size증가는 포인터 증가 이후 여야합니다. 이제 수정되었습니다.
shpc
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.