Skip to content

补充一段JSON number解析代码 #258

Open
@Barenboim

Description

@Barenboim

相比strtod,效率更高并且Locale-independant,支持最长1,000,000个字符长度的数字:

#include <ctype.h>
#include <math.h>

double evaluate_json_number(const char *integer, const char *fraction, int exp)
{
	long long mant = 0;
	int figures = 0;
	double num;
	int sign;

	sign = (*integer == '-');
	if (sign)
		integer++;

	if (*integer != '0')
	{
		mant = *integer - '0';
		integer++;
		figures++;
		while (isdigit(*integer) && figures < 18)
		{
			mant *= 10;
			mant += *integer - '0';
			integer++;
			figures++;
		}

		while (isdigit(*integer))
		{
			exp++;
			integer++;
		}
	}
	else
	{
		while (*fraction == '0')
		{
			exp--;
			fraction++;
		}
	}

	while (isdigit(*fraction) && figures < 18)
	{
		mant *= 10;
		mant += *fraction - '0';
		exp--;
		fraction++;
		figures++;
	}

	if (exp != 0 && figures != 0)
	{
		while (exp > 0 && figures < 18)
		{
			mant *= 10;
			exp--;
			figures++;
		}

		while (exp < 0 && mant % 10 == 0)
		{
			mant /= 10;
			exp++;
			figures--;
		}
	}

	num = mant;
	if (exp != 0 && figures != 0)
	{
		if (exp > 291)
			num = INFINITY;
		else if (exp > 0)
			num *= pow(10, exp);
		else if (exp > -309)
			num /= pow(10, -exp);
		else if (exp > -324 - figures)
		{
			num /= pow(10, -exp - 308);
			num /= pow(10, 308);
		}
		else
			num = 0.0;
	}

	return sign ? -num : num;
}

int parse_json_number(const char *cursor, const char **end, double *num)
{
	const char *integer = cursor;
	const char *fraction = "";
	int exp = 0;
	int sign;

	if (*cursor == '-')
		cursor++;

	if (!isdigit(*cursor))
		return -1;

	if (*cursor == '0' && isdigit(cursor[1]))
		return -1;

	cursor++;
	while (isdigit(*cursor))
		cursor++;

	if (*cursor == '.')
	{
		cursor++;
		fraction = cursor;
		if (!isdigit(*cursor))
			return -1;

		cursor++;
		while (isdigit(*cursor))
			cursor++;
	}

	if (*cursor == 'E' || *cursor == 'e')
	{
		cursor++;
		sign = (*cursor == '-');
		if (sign || *cursor == '+')
			cursor++;

		if (!isdigit(*cursor))
			return -1;

		exp = *cursor - '0';
		cursor++;
		while (isdigit(*cursor) && exp < 2000000)
		{
			exp *= 10;
			exp += *cursor - '0';
			cursor++;
		}

		while (isdigit(*cursor))
			cursor++;

		if (sign)
			exp = -exp;
	}

	if (cursor - integer > 1000000)
		return -1;

	*num = evaluate_json_number(integer, fraction, exp);
	*end = cursor;
	return 0;
}

#include <stdio.h>

int main()
{
	const char *text = "4.94e-324";
	const char *end;
	double num;

	parse_json_number(text, &end, &num);
	printf("num = %le, len = %zu\n", num, end - text);
	return 0;
}

完整的json-parser实现:https://github.com/barenboim/json-parser

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions