首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言判斷字串是否為數字:支援整數、十六進制與浮點數的完整實現

     編輯:關於C語言

問題背景

看似簡單的「判斷字串是否為數字」,實則需處理正負號、前導零、十六進制前綴、小數點、科學計數法等細節。標準庫 strtod/strtol 雖可用,但行為寬鬆(如允許尾部垃圾字元),往往不符合嚴格驗證需求。

自定義解析器設計

採用狀態機思路,單次掃描,O(N) 時間,O(1) 空間。定義巨集簡化字元分類:

#define IS_BLANK(c)  ((c)==' ' || (c)=='\t')
#define IS_DIGIT(c)  ((c)>='0' && (c)<='9')
#define IS_ALPHA(c)  (((c)>='a'&&(c)<='z') || ((c)>='A'&&(c)<='Z'))
#define IS_HEX_DIGIT(c) (((c)>='A'&&(c)<='F') || ((c)>='a'&&(c)<='f'))

核心函數 is_number()

/*** 返回值:0=非數字, 1=十進制整數, 2=十六進制整數, 3=浮點數 ***/
int is_number(char *s) {
    if (!s) return 0;
    char *p = s;
    int base = 10, type = 0;

    // 1. 跳過前導空白
    while (IS_BLANK(*p)) p++;

    // 2. 處理正負號
    if (*p == '+' || *p == '-') p++;

    // 3. 首字元必須是數字或小數點
    if (IS_DIGIT(*p) || *p == '.') {
        if (*p != '.') { // 非小數點開頭 → 可能為整數或十六進制
            // 3.1 檢測 0x/0X 前綴
            if (*p == '0' && p[1] && (p[1]=='x' || p[1]=='X')) {
                type = 2; base = 16; p += 2;
            }
            // 3.2 跳過前導零
            while (*p == '0') p++;
            // 3.3 讀取數字(十六進制包含 A-F/a-f)
            while (IS_DIGIT(*p) || (base==16 && IS_HEX_DIGIT(*p))) p++;
        }

        // 4. 處理小數點(僅十進制支援)
        if (base == 10 && *p && *p == '.') {
            type = 3; p++;
            while (IS_DIGIT(*p)) p++; // 讀取小數部分
        }

        // 5. 結束檢查:必須正好到達字串結尾
        if (*p == '\0') return type ? type : 1;
    }
    return 0;
}

測試用例與驗證

#include <stdio.h>
#include <assert.h>

int main() {
    assert(is_number(NULL) == 0);
    assert(is_number("") == 0);
    assert(is_number("9a") == 0);
    assert(is_number("908") == 1);
    assert(is_number("-908") == 1);
    assert(is_number("+09") == 1);
    assert(is_number("-+9") == 0);
    assert(is_number(" 007") == 1);
    assert(is_number("0x9a8F") == 2);
    assert(is_number("-0xAB") == 2);
    assert(is_number("-9.380") == 3);
    assert(is_number("-0xFF.3") == 0); // 十六進制不支援小數
    printf("All tests passed!\n");
    return 0;
}

擴展建議

  • 支援科學計數法(e/E):在浮點數分支後增加指數部分解析
  • 支援底線分隔符(C++14 風格 1_000_000)
  • 返回結構體攜帶解析後的數值(long long/double)

為何不直接用 sscanf?

sscanf(s, "%lf", &d) 會忽略尾部非數字字元(如 "123abc" 視為合法),且難以區分整數/十六進制/浮點數類型。自定義解析器提供嚴格語法檢查與類型區分。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved