《剑指Offer》-20-表示数值的字符串

发布时间 2023-09-09 15:22:02作者: YaosGHC

这种按照一定规则来验证字符串的题看起来很麻烦,想到另外一道类似的是验证 IP 地址

……我觉得我理不清这个判断逻辑以及各个逻辑间的关系以控制逻辑

	bool isNumber(string s) {
		// 首先这个字符串可能得样式为
		// [若干可能的空格][[+/-][num./num.num/.num/num]][E/e][[+/-][num]][若干可能的空格]
		int begin = 0;
		while (s[begin] == ' ' && begin<s.size()) begin++;
		// 得到第一个不为空的位置,开始验证
		if (s[begin] == s.size()) return false;// 一个全是空格的字符串

		int ePlace = begin;
		while (s[ePlace] != 'E' && s[ePlace] != 'e' && ePlace < s.size()) {
			ePlace++;
		}

		if (s[begin] >= 48 && s[begin] <= 57) {
			// 字符是一个数字
		}
		else {
			if (s[begin] == '+' || s[begin] == '-') begin++;
			else 
		}
		return false;
	}

比如:如果我想要从头到尾一个一个可能性地判断就会非常的复杂繁琐,我需要考虑每一种可能,写很多的return falseif()

但是如果想要通过调用函数的方式,我有必须知道每一部分的起始和结束位置

	bool isNumber(string s) {
		// 首先这个字符串可能得样式为
		// [若干可能的空格][[+/-][num./num.num/.num/num]][E/e][[+/-][num]][若干可能的空格]
		int begin = 0;
		while (s[begin] == ' ' && begin<s.size()) begin++;
		// 得到第一个不为空的位置,开始验证
		if (s[begin] == s.size()) return false;// 一个全是空格的字符串

		int ePlace = begin;
		while (s[ePlace] != 'E' && s[ePlace] != 'e' && ePlace < s.size()) {
			ePlace++;
		}
		return false;
	}
	// 判断是不是一个合法的整数
	bool isInteger(string &str,int begin,int end){
		if (begin >= end && str[begin] == '+' || str[begin] == '-' || (str[begin] >= 48 && str[begin] <= 57)) {
			begin++;
			while (str[begin] >= 48 && str[begin] <= 57) {
				begin++;
				if (begin == end) return true;
			}
		}
		return false;
	}
	// 判断是不是一个合法的小数
	bool isDcimal(string &str,int begin,int end) {
		if (begin >= end) return false;
		if (str[begin] == '+' || str[begin] == '-') begin++;
		else if (str[begin] >= 48 && str[begin] <= 57) {
			// 是一个数字,后面可以是小数点也可以是数字
			begin++;
		}
		else if (str[begin == '.']) {
			// 小数点开头,后面必须有数字
			begin++;
			while (str[begin] >= 48 && str[begin] <= 57) {
				begin++;
				if (begin == end) return true;
			}
		}
		return false;
	}

不管是哪样,这么分类讨论太麻烦了,而且也很容易出错

书上官解

官解和力扣题目有差异,力扣要求更多,主要是会有空格,前后中间都有可能有空格

给官解打了补丁 AC

	bool isNumber(string s) {
		const char* pointer = s.c_str();// 获取字符指针

		while (*pointer == ' ') ++pointer;// 跳过前导空格

		bool numeric = scanInteger(&pointer);

		if (*pointer == '.') {
			++pointer;
			/*
			* 为什么会有||运算?
			* 小数点前面可有可无,后面可有可无,但是不能都无
			* [带符号数字].[不带符号数字]
			*/
			numeric = scanUnsignedInteger(&pointer) || numeric;
		}

		if (*pointer == 'E' || *pointer == 'e') {
			++pointer;
			// E前面和后面都必须有数字
			numeric = scanInteger(&pointer) && numeric;
		}
		// 如果指针停在了空格,需要检查空格后面还有没有字符
		if (numeric) {
			while (*pointer == ' ') ++pointer;
			return *pointer == '\0';
		}

		return false;
	}

	bool scanInteger(const char** str) {
		if (**str == '+' || **str == '-') ++(*str);
		return scanUnsignedInteger(str);
	}

	bool scanUnsignedInteger(const char** str) {
		const char* before = *str;
		while (**str != '\0' && **str!=' ' && **str >= '0' && **str <= '9') ++(*str);
		return *str > before;// 是有效长度的字符串,只要字符串存在从当前位置开始的一段数字就返回true
	}

后面有机会的话试着当做一个 正则表达式的练习题题做一遍