web-dev-qa-db-ja.com

Cで文字列から部分文字列を抽出する方法は?

Strncmpを使用してみましたが、抽出する特定のバイト数を指定した場合にのみ機能します。

char line[256] = This "is" an example. //I want to extract "is"
char line[256] = This is "also" an example. // I want to extract "also"
char line[256] = This is the final "example".  // I want to extract "example"
char substring[256]

「」の間のすべての要素をどのように抽出しますか?変数部分文字列に入れますか?

7
ShadyBears

注:strtokは_const char*_変数を操作したくないため、コードを記述したときに問題が発生することがわかったので、この回答を編集しました。これは、根本的な原則の問題というよりは、私がこの例をどのように書いたかのアーティファクトでしたが、どうやらそれは二重の反対票に値しました。そこで修正しました。

次の作品(Mac OS 10.7でgccを使用してテスト済み):

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

int main(void) {
const char* lineConst = "This \"is\" an example"; // the "input string"
char line[256];  // where we will put a copy of the input
char *subString; // the "result"

strcpy(line, lineConst);

subString = strtok(line,"\""); // find the first double quote
subString=strtok(NULL,"\"");   // find the second double quote

printf("the thing in between quotes is '%s'\n", subString);
}
_

動作方法は次のとおりです。strtokは「区切り文字」(2番目の引数)を探します-この場合、最初の_"_。内部的には、「どこまで到達したか」を認識しており、最初の引数としてNULLを(_char*_ではなく)使用して再度呼び出すと、そこから再び開始されます。したがって、2番目の呼び出しでは、「最初と2番目の二重引用符の間の文字列」が返されます。あなたが欲しかったのはそれです。

警告:strtokは通常、区切り文字を_'\0'_に置き換えます。したがって、このアプローチによって変更される入力文字列を当てにする必要があります。それが受け入れられない場合は、最初にローカルコピーを作成する必要があります。本質的に、文字列定数を変数にコピーするときに上記のようにします。後でline=malloc(strlen(lineConst)+1);free(line);を呼び出してこれを行う方がきれいですが、これを関数内にラップする場合は、戻り値が残っている必要があることを考慮する必要があります関数が戻った後に有効... strtokは文字列内の正しい場所へのポインタを返すため、トークンのコピーは作成されません。結果を取得するスペースへのポインターを渡し、関数内にそのスペースを(正しいサイズで)作成してから、結果をそのスペースにコピーするのが適切です。これはすべて微妙です。これが不明な場合はお知らせください!

8
Floris

ライブラリをサポートせずに実行したい場合...

_void extract_between_quotes(char* s, char* dest)
{
   int in_quotes = 0;
   *dest = 0;
   while(*s != 0)
   {
      if(in_quotes)
      {
         if(*s == '"') return;
         dest[0]=*s;
         dest[1]=0;
         dest++;
      }
      else if(*s == '"') in_quotes=1;
      s++;
   }
}
_

それを呼ぶ

extract_between_quotes(line, substring);

1
Keith Nicholas

これを行うには長い方法があります:抽出される文字列が引用符で囲まれていると仮定します(以下のコメントでキースによって提案されたエラーチェックのために修正されました)

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

int main(){

    char input[100];
    char extract[100];
    int i=0,j=0,k=0,endFlag=0;

    printf("Input string: ");
    fgets(input,sizeof(input),stdin);
    input[strlen(input)-1] = '\0';

    for(i=0;i<strlen(input);i++){
        if(input[i] == '"'){

                j =i+1;
                while(input[j]!='"'){
                     if(input[j] == '\0'){
                         endFlag++;
                         break;
                     }
                     extract[k] = input[j];
                     k++;
                     j++;
                }
        }
    }
    extract[k] = '\0';

    if(endFlag==1){
        printf("1.Your code only had one quotation mark.\n");
        printf("2.So the code extracted everything after that quotation mark\n");
        printf("3.To make sure buffer overflow doesn't happen in this case:\n");
        printf("4.Modify the extract buffer size to be the same as input buffer size\n");

        printf("\nextracted string: %s\n",extract);
    }else{ 
       printf("Extract = %s\n",extract);
    }

    return 0;
}

出力(1):

$ ./test
Input string: extract "this" from this string
Extract = this

出力(2):

$ ./test
Input string: Another example to extract "this gibberish" from this string
Extract = this gibberish

出力(3):(キースによって提案されたエラーチェック)

$ ./テスト

Input string: are you "happy now Kieth ?
1.Your code only had one quotation mark.
2.So the code extracted everything after that quotation mark
3.To make sure buffer overflow doesn't happen in this case:
4.Modify the extract buffer size to be the same as input buffer size

extracted string: happy now Kieth ?

---------------------------------------------- -------------------------------------------------- --------------------------------

要求されていませんが-次のコードは、引用符で囲まれている限り、入力文字列から複数の単語を抽出します。

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

int main(){

    char input[100];
    char extract[50];
    int i=0,j=0,k=0,endFlag=0;

    printf("Input string: ");
    fgets(input,sizeof(input),stdin);
    input[strlen(input)-1] = '\0';

    for(i=0;i<strlen(input);i++){
        if(input[i] == '"'){
            if(endFlag==0){
                j =i+1;
                while(input[j]!='"'){
                     extract[k] = input[j];
                     k++;
                     j++;
                }
                endFlag = 1;
            }else{
               endFlag =0;
            }

            //break;
        }
    }

    extract[k] = '\0';

    printf("Extract = %s\n",extract);

    return 0;
}

出力:

$ ./test
Input string: extract "multiple" words "from" this "string"
Extract = multiplefromstring
0
sukhvir

strchr関数を見てみましたか?その関数を2回呼び出して、"文字の最初と2番目のインスタンスへのポインターを取得し、memcpyとポインター演算の組み合わせを使用して必要なものを取得できる必要があります。

0
godel9
#include <string.h>
...        
substring[0] = '\0';
const char *start = strchr(line, '"') + 1;
strncat(substring, start, strcspn(start, "\""));

境界とエラーチェックが省略されました。 strtokには副作用があるため、避けてください。

0
fizzer