我阅读了一篇关于验证 IP 地址 (IPv4) 字符串表示的程序的文章。我认为这是一种有趣的、负担得起的、非常好的编程实践材料。
它看起来很有趣,所以我决定尝试编写一个程序。下面的文章将为您提供一步一步的方法。
组织语法
一个IP地址是一个从0到255的四个值的列表,每个值用句点分隔。
如果我们结合共同的部分,我们可以写:
从状态转移图中看到的语法
语法图显示了接受什么样的语法,但是在制作程序时,如果你换个角度,把注意力集中在“状态”上,你会看到状态会随着输入的变化而变化。
换句话说,在所谓的状态转移图中,将语法图中输入之间的连线部分提取为状态,将输入表示为连接状态的连线的形状。 (这里,$ 是终止的术语。)
即使在这个简单的例子中,线条也会变得混乱。状态转换也可以用表格形式表示。让我们将其转换为一个表格,该表格从当前状态和输入中派生出下一个状态。
| 输入 | 开始 | 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