真实面经题目 · 原创解析

如何实现 str2num,将字符串转换为整数或浮点数?

str2num 的重点是把符号、前导零、整数部分、小数部分、非法字符和溢出规则定义清楚,再用状态机或分段扫描实现。

出现于:百度 · 算法

60 秒回答模板

实现 str2num 不能只调用 parseInt。先跳过可选空白,处理正负号,再扫描整数部分;如果支持浮点数,遇到小数点后继续扫描小数部分,用 base 逐位缩小贡献。要定义非法输入、多个符号、多个小数点、空字符串、前导零、溢出和精度损失怎么处理。整数可在累乘 10 前做边界判断,浮点可分为 sign、integer、fraction 三段计算。面试中最好把它讲成有限状态机:start、sign、integer、dot、fraction、end、invalid。

考点 语法定义
难度 真实面经题
回答目标 讲清原理、实现和边界

深入解析

01

先定义语法

允许哪些输入要先说清楚,例如空白、正负号、前导零、小数点、是否支持科学计数法、遇到非法字符是报错还是截断。

02

整数部分扫描

符号处理后逐字符读取数字,value = value * 10 + digit。每次累乘前检查是否超过目标整数范围,避免溢出后才发现。

03

小数部分扫描

支持浮点数时,小数点后每个 digit 按 0.1、0.01 等权重累加,或分别记录 fractional 和 scale,最后统一除以 scale。

04

状态机更稳

用状态机处理 start、sign、integer、dot、fraction、end、invalid,可以系统约束字符顺序,避免多个符号或多个小数点被误接受。

05

返回和错误策略

工程实现要明确错误返回值、异常、NaN、clamp 到边界还是返回解析失败。面试题通常更看重边界定义和代码可维护性。

javascript

分段扫描 sign、integer 和 fraction

function str2num(input) {
  const s = input.trim();
  if (!s) throw new Error('empty input');
  let i = 0;
  let sign = 1;
  if (s[i] === '+' || s[i] === '-') {
    sign = s[i] === '-' ? -1 : 1;
    i += 1;
  }

  let integer = 0;
  let digits = 0;
  while (i < s.length && s[i] >= '0' && s[i] <= '9') {
    integer = integer * 10 + (s.charCodeAt(i) - 48);
    i += 1;
    digits += 1;
  }

  let fraction = 0;
  let scale = 1;
  if (s[i] === '.') {
    i += 1;
    while (i < s.length && s[i] >= '0' && s[i] <= '9') {
      fraction = fraction * 10 + (s.charCodeAt(i) - 48);
      scale *= 10;
      i += 1;
      digits += 1;
    }
  }

  if (digits === 0 || i !== s.length) throw new Error('invalid number');
  return sign * (integer + fraction / scale);
}
  • 示例 `-2131` 和 `+002131.00143` 都由同一套 sign/integer/fraction 流程覆盖。
  • 如果题目要求 32 位整数,需要在 `integer * 10 + digit` 前加入边界判断。

易错点

  • 不要只处理正常数字字符串,符号、空串、小数点和非法字符都要覆盖。
  • 不要溢出后再判断,数值可能已经越界。
  • 不要把浮点精度说成完全精确,二进制浮点本身会有表示误差。

面试官追问

如何支持科学计数法?

在 fraction 后增加 exponent 状态,处理 e/E、指数符号和指数数字,最后按 10 的指数调整结果。

整数溢出怎么判断?

在 value > (MAX - digit) / 10 时提前判定溢出,再按约定报错或截断到边界。

为什么不要直接调用库函数?

手写题考察边界、状态和数值表示,直接调用库函数无法展示这些设计。