需解析字符串提取兩個操作數和運算符,格式可能帶括號 `(-5)+(-6)` 或不帶 `5+6`。單一 `sscanf` 格式串難以兼容兩種格式。
void remove_parentheses(char *str) {
char *src = str, *dst = str;
while (*src) {
if (*src != '(' && *src != ')') {
*dst++ = *src;
}
src++;
}
*dst = '\0';
}
// 測試
char expr1[] = "(-5)+(-6)";
char expr2[] = "5+6";
remove_parentheses(expr1); // 變為 "-5+-6" (注意雙符號)
remove_parentheses(expr2); // 保持 "5+6"
注意:`(-5)+(-6)` 移除括號後變為 `-5+-6`,出現連續符號,需進一步規範化或解析器支持負數。
// 簡單版:確保運算符前後有空格
void normalize_ops(char *str) {
// 實現略:遍歷插入空格,處理負數符號不加空格
// 如 "-5+-6" -> "-5 + -6" 或 "-5 + (-6)" 視解析器而定
}
// 假設規範化後為 "操作數 運算符 操作數" 格式,如 "-5 + -6" 或 "5 + 6"
int parse_expression(const char *str, double *a, char *op, double *b) {
// 格式:%lf 跳過空格讀雙精度, %c 讀運算符(含符號), %lf 讀第二數
// 注意:%c 不跳過空格,需在格式串加空格 "%lf %c %lf"
int ret = sscanf(str, "%lf %c %lf", a, op, b);
return ret == 3; // 成功解析三項
}
// 測試
double n1, n2; char oper;
parse_expression("-5 + -6", &n1, &oper, &n2); // n1=-5, oper='+', n2=-6 成功
parse_expression("5 + 6", &n1, &oper, &n2); // n1=5, oper='+', n2=6 成功
typedef struct {
double left;
char op;
double right;
bool valid;
} ExprResult;
ExprResult parse_flexible(const char *input) {
ExprResult res = {0};
char buf[256];
strncpy(buf, input, sizeof(buf)-1);
// 1. 移除所有括號
remove_parentheses(buf);
// 2. 規範化:運算符前後加空格,合併連續符號 (-- -> +, +- -> -)
normalize_operators(buf); // 需實現符號合併邏輯
// 3. 解析
if (sscanf(buf, "%lf %c %lf", &res.left, &res.op, &res.right) == 3) {
res.valid = true;
}
return res;
}
對於計算器類應用,建議直接實現遞歸下降解析器或Shunting-yard 算法 (參考文章 26442),原生支持括號、優先級、負數、函數,比 `sscanf` 組合更清晰、可擴展。
`sscanf` 單一格式串無法同時匹配帶/不帶括號格式。工程上採用 **預處理移除括號 → 規範化運算符格式 → 固定格式 `sscanf` 解析** 三步走策略。長遠看,手寫表達式解析器 (遞歸下降/Shunting-yard) 是更專業、可維護的選擇。