我阅读了一篇关于验证 IP 地址 (IPv4) 字符串表示的程序的文章。我认为这是一种有趣的、负担得起的、非常好的编程实践材料。

它看起来很有趣,所以我决定尝试编写一个程序。下面的文章将为您提供一步一步的方法。

组织语法

一个IP地址是一个从0到255的四个值的列表,每个值用句点分隔。

IPアドレスを構文解析する

如果我们结合共同的部分,我们可以写:

IPアドレスを構文解析する

从状态转移图中看到的语法

语法图显示了接受什么样的语法,但是在制作程序时,如果你换个角度,把注意力集中在“状态”上,你会看到状态会随着输入的变化而变化。

换句话说,在所谓的状态转移图中,将语法图中输入之间的连线部分提取为状态,将输入表示为连接状态的连线的形状。 (这里,$ 是终止的术语。)

即使在这个简单的例子中,线条也会变得混乱。状态转换也可以用表格形式表示。让我们将其转换为一个表格,该表格从当前状态和输入中派生出下一个状态。

输入 开始 S1 S2 S3 S4 S5
0 S5 S3 S3 S5 S5 错误
1 S1 S3 S3 S5 S5 错误
2 S2 S3 S3 S5 S5 错误
3 S3 S3 S3 S5 S5 错误
4 S3 S3 S3 S5 S5 错误
5 S3 S3 S4 S5 S5 错误
6 S3 S3 S5 S5 错误 错误
7 S3 S3 S5 S5 错误 错误
8 S3 S3 S5 S5 错误 错误
9 S3 S3 S5 S5 错误 错误
$ 错误 完成 完成 完成 完成 完成

不用说,表格是在程序中使用的一种非常方便的格式。您可以按原样将其设为二维数组。

程序

当我根据上面的想法编写程序时,最终变成了这个样子。

地址解析.h
// 文字列表現の 0~255 を解釈して返却値で返す。
// 解釈に成功した場合は残りの文字列の位置を rest にセットする。
// エラーの場合は -1 を返し、 rest は問題のある箇所がセットされる。
int parse_number(const char* input, const char** rest);

// IP アドレスの文字列表現をパースして result に格納する。
// 正しいフォーマットとしてパースが完了した場合には 1 を返し、
// そうでなかった場合には 0 を返す。
// 0 が返されたときは result の内容は信頼できない。
_Bool parse_address(const char* input, unsigned char result[static 4]);
地址解析.c
#include "address_parse.h"

#include <stdio.h>

// 状態遷移表
// -1 はエラー、 -2 は完了を表す
static const int state_tranition[][6] = {
    {5, 3, 3, 5, 5, -1},
    {1, 3, 3, 5, 5, -1},
    {2, 3, 3, 5, 5, -1},
    {3, 3, 3, 5, 5, -1},
    {3, 3, 3, 5, 5, -1},
    {3, 3, 4, 5, 5, -1},
    {3, 3, 5, 5, -1, -1},
    {3, 3, 5, 5, -1, -1},
    {3, 3, 5, 5, -1, -1},
    {3, 3, 5, 5, -1, -1},
    {-1, -2, -2, -2, -2, -2}};

int parse_number(const char* input, const char** rest) {
    int state = 0, result = 0;
    while (1) {
        int ch = *input;
        // 数値でないものは仮に 10 として扱う
        ch = (ch >= '0' && ch <= '9') ? ch - '0' : 10;
        state = state_tranition[ch][state];
        if (state < 0) break;
        result = result * 10 + ch;
        input++;
    }

    *rest = input;
    return state == -2 ? result : -1;
}

_Bool parse_address(const char* input, unsigned char result[static 4]) {
    const char* rest = input;
    for (int i = 0;; ++i) {
        int r = parse_number(rest, &rest);
        if (r == -1) return 0;
        result[i] = r;
        if (i == 3) {
            if (*rest != '

原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308631970.html

相关文章: