8

Cで正規表現を使用しています(「regex.h」ライブラリを使用)。regcomp(...) と regexec(...) の標準呼び出し (およびチェック) を設定した後、コンパイルした正規表現に一致する実際の部分文字列のみを出力できます。マニュアルページによると、regexec を使用するということは、部分文字列の一致を「regmatch_t」として知られる構造に格納することを意味します。構造体には、メモリ内の一致した部分文字列の文字のアドレスであると私が理解しているものを参照するための rm_so と rm_eo のみが含まれていますが、これらをオフセットと 2 つのポインターに使用して実際の部分文字列を抽出し、それを配列 (理想的には文字列の 2D 配列)?

標準出力に出力するだけで機能しますが、同じ設定を使用して文字列/文字配列に保存しようとすると、式との照合に最初に使用された文字列全体が保存されます。さらに、print ステートメント内の「%.*s」とは何ですか? 文字配列へのポインターを正しく読み取るのは、それ自体が正規表現だと思います。一致した部分文字列をコレクション内に保存して、ソフトウェアの他の場所で作業できるようにしたいだけです。

背景: p と p2 はどちらも、以下のコードで while ループに入る前に、一致する文字列の先頭を指すように設定されたポインターです。以下に示すメインループの前に]

int ind = 0;
while(1){
    regExErr1 = regexec(&r, p, 10, m, 0);
    //printf("Did match regular expr, value %i\n", regExErr1);
    if( regExErr1 != 0 ){ 
        fprintf(stderr, "No more matches with the inherent regular expression!\n"); 
        break; 
    }   
    printf("What was found was: ");
    int i = 0;
    while(1){
        if(m[i].rm_so == -1){
            break;
        }
        int start = m[i].rm_so + (p - p2);
        int finish = m[i].rm_eo + (p - p2);
        strcpy(matches[ind], ("%.*s\n", (finish - start), p2 + start));
        printf("Storing:  %.*s", matches[ind]);
        ind++;
        printf("%.*s\n", (finish - start), p2 + start);
        i++;
    }
    p += m[0].rm_eo; // this will move the pointer p to the end of last matched pattern and on to the start of a new one
}
printf("We have in [0]:  %s\n", temp);
4

2 に答える 2

10

正規表現パッケージはたくさんありますが、あなたのものは POSIX のものと一致するようです:regcomp()など.

それが定義する 2 つの構造は次の<regex.h>とおりです。

  • regex_t少なくともsize_t re_nsub、括弧で囲まれた部分式の数を含む。

  • regmatch_t少なくともregoff_t rm_so、文字列の先頭から部分文字列の先頭までregoff_t rm_eoのバイト オフセット、および文字列の先頭から部分文字列の末尾の後の最初の文字のバイト オフセットを含む。

「オフセット」はポインターではなく、文字配列へのインデックスであることに注意してください。

実行関数は次のとおりです。

  • int regexec(const regex_t *restrict preg, const char *restrict string, size_t nmatch, regmatch_t pmatch[restrict], int eflags);

印刷コードは次のようになります。

for (int i = 0; i <= r.re_nsub; i++)
{
    int start = m[i].rm_so;
    int finish = m[i].rm_eo;
//  strcpy(matches[ind], ("%.*s\n", (finish - start), p + start));  // Based on question
    sprintf(matches[ind], "%.*s\n", (finish - start), p + start);   // More plausible code
    printf("Storing:  %.*s\n", (finish - start), matches[ind]);     // Print once
    ind++;
    printf("%.*s\n", (finish - start), p + start);                  // Why print twice?
}

sprintf()文字列のコピー ( 経由) がターゲット文字列をオーバーフローしないように、コードをアップグレードする必要があるsnprintf()ことに注意してくださいsprintf()。文字列の開始と終了を印刷でマークすることもお勧めします。例えば:

    printf("<<%.*s>>\n", (finish - start), p + start);

これにより、ヒープ全体がスペースなどを見やすくなります。

[将来的には、MCVE ( Minimal, Complete, Verifiable Example ) または SSCCE ( Short, Self-Contained, Correct Example ) を提供して、人々がより簡単に支援できるようにしてください。]

これは私が作成した SSCCE で、おそらく 2010 年の別の SO の質問への回答です。いくつかの機能の本質を示す小さなプログラム (この場合は POSIX 正規表現など)。メモリージョガ​​ーとして重宝します。

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

#define tofind    "^DAEMONS=\\(([^)]*)\\)[ \t]*$"

int main(int argc, char **argv)
{
    FILE *fp;
    char line[1024];
    int retval = 0;
    regex_t re;
    regmatch_t rm[2];
    //this file has this line "DAEMONS=(sysklogd network sshd !netfs !crond)"
    const char *filename = "/etc/rc.conf";

    if (argc > 1)
        filename = argv[1];

    if (regcomp(&re, tofind, REG_EXTENDED) != 0)
    {
        fprintf(stderr, "Failed to compile regex '%s'\n", tofind);
        return EXIT_FAILURE;
    }
    printf("Regex: %s\n", tofind);
    printf("Number of captured expressions: %zu\n", re.re_nsub);

    fp = fopen(filename, "r");
    if (fp == 0)
    {
        fprintf(stderr, "Failed to open file %s (%d: %s)\n", filename, errno, strerror(errno));
        return EXIT_FAILURE;
    }

    while ((fgets(line, 1024, fp)) != NULL)
    {
        line[strcspn(line, "\n")] = '\0';
        if ((retval = regexec(&re, line, 2, rm, 0)) == 0)
        {
            printf("<<%s>>\n", line);
            // Complete match
            printf("Line: <<%.*s>>\n", (int)(rm[0].rm_eo - rm[0].rm_so), line + rm[0].rm_so);
            // Match captured in (...) - the \( and \) match literal parenthesis
            printf("Text: <<%.*s>>\n", (int)(rm[1].rm_eo - rm[1].rm_so), line + rm[1].rm_so);
            char *src = line + rm[1].rm_so;
            char *end = line + rm[1].rm_eo;
            while (src < end)
            {
                size_t len = strcspn(src, " ");
                if (src + len > end)
                    len = end - src;
                printf("Name: <<%.*s>>\n", (int)len, src);
                src += len;
                src += strspn(src, " ");
            }
        }
    } 
    return EXIT_SUCCESS;
}

DAEMONS=これは、ファイルで始まる特定の行を見つけるように設計されています/etc/rc.conf(ただし、コマンド ラインで別のファイル名を指定できます)。目的に合わせて簡単に調整できます。

于 2013-03-06T04:05:29.630 に答える