【副業】IPV4アドレスの正当性を判定するC言語プログラミング(正規表現を使用)

IPV4アドレスの正当性判定をC言語プログラミングで実現(正規表現を利用)

私をよく知っている友人たちは、いくつかの印象を持っているかもしれませんが、N年前にこのテーマについてブログに書きましたが、当時、私は仕事でこの問題に実際に遭遇しました。作業が終わったらコードを追加してこの問題を解決しようと思っていたのですが、結局数年も放置してしまっていて、本当に恥ずかしいです。現在、コードのこの部分は公開されており、誰でもダウンロードしてテストすることができます。

1 前に書いてある

以前、C言語プログラミングを使ってIPV4アドレスの正当性を判定する方法を主に紹介したブログ記事を書きましたが、その時はC言語のネイティブ関数を使って実現しました。 C 言語プログラミングでは、正規表現を使用してこの機能要件を満たします。

2 正規表現とは何ですか

正規表現は、テキスト パターンを照合するためのツールです。特定の文字と文法規則を通じてテキスト パターンを記述し、テキスト内のパターンに一致する文字列を検索できます。正規表現は、テキストの検索、置換、検証などのさまざまなアプリケーション シナリオで使用でき、プログラマーやテキスト処理作業者にとって必要なツールの 1 つです。

一部の高級プログラミング言語では、正規表現を呼び出すための成熟したライブラリ インターフェイスがありますが、C 言語ではそのような例はほとんどありません。しかし、使えないわけではなく、実際には使えるのです。

C で正規表現を使用する場合は、注意すべき点がいくつかあります。

  1. regex.hまずヘッダー ファイルをインクルードする必要があります。
  2. 正規表現を使用する前に、regcomp()関数を使用して正規表現をパターンにコンパイルする必要があります。
  3. regexec()関数を使用して正規表現を実行する場合、REG_EXTENDEDオプションを使用して拡張正規表現を有効にしたり、REG_ICASEオプションを使用して大文字と小文字を区別したりできます。
  4. 関数を使用する場合regexec()、戻り値が 0 の場合は一致が成功したことを意味し、戻り値が 0 の場合はREG_NOMATCH一致がなかったことを意味し、戻り値がそれ以外の値の場合はエラーが発生したことを意味します。
  5. この関数を使用してエラー情報を取得する場合はregerror()、バッファーとバッファー サイズを指定する必要があります。
  6. 正規表現を使用した後、regfree()関数を使用してコンパイルされたパターンを解放する必要があります。
  7. 正規表現内の特殊文字はエスケープする必要があります。たとえば、.と記述する必要があります\.。そうしないと、任意の文字と一致します。
  8. 正規表現内の括弧は、IP アドレスの照合などのグループ化に使用できます([0-9]{1,3}\.){3}[0-9]{1,3}
  9. 正規表現の照合では大量の CPU リソースが消費される可能性があるため、正規表現を使用する場合はパフォーマンスの問題に注意する必要があります。strstr()関数など、より単純な文字列一致アルゴリズムの使用を検討してください。

正規表現の詳細については、「正規表現言語 - クイック リファレンス | Microsoft Learn」を参照してください。

3 需要分析

実は、このトピックの要件は非常に単純で、文字列を入力して、それが正当な IPv4 アドレスであるかどうかを判断します。機能だけ見ると非常にシンプルに見えますが、完璧にするには少し努力が必要です。私の言うことが信じられない場合は、以下の分解図を見てください。

IPV4 の画像結果

4 C言語版(正規表現)

単純なバージョンから始めて、コードを直接見てみましょう。

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

#include <regex.h>

static int is_valid_ipv4_regex(const char *ip_address)
{
    
    
    regex_t regex;
    int reti;

    // Compile regular expression
    reti = regcomp(&regex, "^([0-9]{1,3}\\.){3}[0-9]{1,3}$", REG_EXTENDED);
    if (reti) {
    
    
        fprintf(stderr, "Could not compile regex\n");
        reti = 0;
    }

    // Execute regular expression
    printf("%s\n", ip_address);
    reti = regexec(&regex, ip_address, 0, NULL, 0);
    if (!reti) {
    
    
        printf("Valid IP address %d\n", reti);
        reti = 1;
    } else if (reti == REG_NOMATCH) {
    
    
        printf("Invalid IP address xxx %d\n", reti);
        reti = 0;
    } else {
    
    
        char error_message[100];
        regerror(reti, &regex, error_message, sizeof(error_message));
        fprintf(stderr, "Regex match failed: %s\n", error_message);
        reti = 0;
    }

exit_entry:

    // Free compiled regular expression
    regfree(&regex);

    return reti;
}


int is_valid_ipv4(const char *ip_address) 
{
    
    
    int num, dots = 0;
    char *ptr;

    if (ip_address == NULL) {
    
    
        return 0;
    }

    ptr = strtok((char *)ip_address, ".");
    if (ptr == NULL) {
    
    
        return 0;
    }

    while (ptr) {
    
    
        if (!isdigit(*ptr)) {
    
    
            return 0;
        }

        if (*ptr == '0') {
    
     //check start '0'
            return 0;
        }

        num = atoi(ptr);
        if (num < 0 || num > 255) {
    
    
            return 0;
        }

        ptr = strtok(NULL, ".");
        if (ptr != NULL) {
    
    
            dots++;
        }
    }

    if (dots != 3) {
    
    
        return 0;
    }

    if (atoi(ip_address) >= 1 && atoi(ip_address) <= 126) {
    
    
        printf("This is a Class A IP address.\n");
        return 1;
    } else if (atoi(ip_address) >= 128 && atoi(ip_address) <= 191) {
    
    
        printf("This is a Class B IP address.\n");
        return 1;
    } else if (atoi(ip_address) >= 192 && atoi(ip_address) <= 223) {
    
    
        printf("This is a Class C IP address.\n");
        return 1;
    } else {
    
    
        printf("This is not a Class A, B, or C IP address.\n");
        return 0;
    }

    return 1;
}

int check_is_valid_ipv4(const char *ip)
{
    
    
    int ret = 0;
    
    //ret = is_valid_ipv4(ip); 
    ret = is_valid_ipv4_regex(ip); 

    return ret; 
}

int main(int argc, const char *argv[])
{
    
    
    const char *ip = argv[1];

    printf("check %s\n", ip);
    printf("ret %d\n", check_is_valid_ipv4(ip));
}

コンパイルして実行すると、「192.168.0.1」など一般的なipv4アドレスを入力しても問題ありませんが、不正な文字を入力するとエラーが報告されます。

recan@ubuntu:~$ 
recan@ubuntu:~$ 
recan@ubuntu:~$ ./test 192.168.1.3
check 192.168.1.3
192.168.1.3
Valid IP address 0
ret 1
recan@ubuntu:~$ ./test 192.168.1.t
check 192.168.1.t
192.168.1.t
Invalid IP address xxx 1
ret 0
recan@ubuntu:~$ 
recan@ubuntu:~$ ./test 192.168.1.oo
check 192.168.1.oo
192.168.1.oo
Invalid IP address xxx 1
ret 0
recan@ubuntu:~$ 
recan@ubuntu:~$ ./test 192.168.01.8
check 192.168.01.8
192.168.01.8
Valid IP address 0
ret 1
recan@ubuntu:~$ 
recan@ubuntu:~$

ただし、注意深い友人であれば、IP アドレスの特定のセグメントの先頭に 0 がある場合、それが正しい IP アドレスであると判断されるようですが、実際にはこのように書くことは一般的ではないことに気づくかもしれません。

では、どうすればこの状況を回避できるのでしょうか?

正規表現で実行することは可能でしょうか?

この質問は読者が自分で調べることに委ねられていますが、正規表現の学習としては非常に興味深いものです。

この機能が完成すれば、より深く正規表現を使いこなすことができると思います。

5 つの完全なテスト ケース

このセクションでは、コードのテストに役立つように、さまざまなテスト ケースを追加します。

合法的测试输入
192.168.0.1
10.0.0.1
172.16.0.1
255.255.255.255

非法的测试输入
256.0.0.1
192.168.0.0.1
192.168.0
192.168.0.1.2

非法的测试输入
256.0.0.1
192.168.0.0.1
192.168.0
192.168.0.1.2
300.300.300.300
1.2.3
1.2.3.4.5
1.2.3.4.
.1.2.3.4
1..2.3.4

テスト ケースは常に充実しており、誰でも追加することができます。

おすすめ

転載: blog.csdn.net/szullc/article/details/130836188