也许大家都没碰到过这样的报错: “错误: 无法识别的字符: 4” --TypeError: unsupported operand type(s) for -: ‘str‘ and ‘float‘

用AI辅助写了一个小项目,尝试写一个使用中文操作符和同像性编程的语言。写好需求后,AI帮我写了架构设计,并写了编码实现。

在使用unittest进行项目测试的时候,碰到如下报错:

.====x is 错误: 无法识别的字符: 4, x.type:<class 'str'>
E.
======================================================================
ERROR: test_math_functions (__main__.TestCNPLInterpreter)
测试数学函数
----------------------------------------------------------------------
Traceback (most recent call last):
  File "E:\work\cntrae\test_parser.py", line 26, in test_math_functions
  File "e:\py310\lib\unittest\case.py", line 876, in assertAlmostEqual
    diff = abs(first - second)
TypeError: unsupported operand type(s) for -: 'str' and 'float'

也就是使用代码assertAlmostEqual(self.interpreter.interpret("4 开方"), 2.0)

进行相等测试的时候,因为类型不匹配而报错。

问题回顾 和解决

事情是这样的,在编程涉及到数学计算的处理,要求是能识别两元或三元操作符,三元操作符是主谓宾,两元操作符可以看做主宾,类似这样的:
"5 加 3"

"4 乘 2"

"4 开方"

"0 余弦"

使用Trae和RooCode辅助编程。其中Trae刚开始使用了DeepSeek-v3模型,因为上面的报错,单独写了测试语句如下:

from cnpl_interpreter import CNPLInterpreter

interpreter = CNPLInterpreter()
x = interpreter.interpret("4 开方")
print(f"====x is {x}, x.type:{type(x)}")
print(x)

碰到了这个报错:

PS E:\work\cntrae> python test_2d.py
====1词法分析器: input_str:4 开方
====2无法识别的字符: 4
====x is 错误: 无法识别的字符: 4, x.type:<class 'str'>
错误: 无法识别的字符: 4

有错误就让Trae改呗,结果改了几十遍,都没改对。

Trae的修改

问题出在词法分析器对数字和操作符的处理顺序上。建议修改lexer方法,确保优先识别数字,然后才是操作符。需要调整token_types中number和operator的匹配顺序,并添加对单操作数数学函数的特殊处理。

我将修改lexer方法,调整数字和操作符的匹配顺序,确保优先识别数字,以解决'4 开方'这样的语句导致的错误。

cnpl_interpreter.py

失败

我将重新尝试修改lexer方法,确保数字和操作符的匹配顺序正确,优先识别数字后才是操作符。

cnpl_interpreter.py

+ 0 - 10

审查

我将调整lexer方法中数字和操作符的匹配顺序,确保优先识别数字,以解决'4 开方'这样的语句导致的错误。

cnpl_interpreter.py

+ 10 - 0

审查

已修复词法分析器中对数字和操作符的处理顺序问题,现在可以正确处理'4 开方'这样的语句。修改后的lexer方法会优先识别数字,然后再检查操作符,避免了之前的错误。

问题定位确实正确,但是改了几十遍还是错,估计陷入了AI模型的死循环了。

柳暗花明

就我个人而言,刚开始手工加print断点,但是没有新信息打印出来,一筹莫展不知道该怎么调试。

后来从报错信息突然想到: 是不是这个4就是个字符,但是无法识别呢? 离真相很近了,但是我误以为这个4就是ASCII里的第四个字符,导致无法识别。

再后来,我突然明白了,x的返回值就是:“错误: 无法识别的字符: 4” 这么一长串字符串。

在我知道问题所在后,再次给AI指出来,但是AI还是陷在错误的谜团里。于是我做了一个违背自己习惯的决定,就是用豆包替换DeepSeek-v3 ,之所以敢让豆包上,是因为我知道豆包这个模型比较稳妥,同时它也并不像一些人认为的跟国际顶级大模型有较大的差距。

果然,换了豆包后,我把有问题的代码段,以及promtp:“这段代码有问题,碰到“4 开方” 这样的语句,会导致出错:错误: 无法识别的字符: 4” 发送给豆包,豆包帮我修改,您猜怎么着? 一把过!

这是测试时的正常的输出是:

PS E:\work\cntrae> python test_2d.py
====1词法分析器: input_str:4 开方
====11 理单操作数函数predicate:开方
====12执行单操作数函数: 开方(4)
====13操作数转换成功: 4 -> 4.0
====开方结果: 2.0
====x is 2.0, x.type:<class 'float'>
2.0

可以看到,我写了5个print断点检测,但是如果早一天给豆包,可能就没手工写断点这些事情了。

这是unittest测试的输出结果:

PS E:\work\cntrae> python .\test_parser.py
.====1词法分析器: input_str:4 开方
====11 理单操作数函数predicate:开方
====12执行单操作数函数: 开方(4)
====13操作数转换成功: 4 -> 4.0
====开方结果: 2.0
====1词法分析器: input_str:0 正弦
====11 理单操作数函数predicate:正弦
====12执行单操作数函数: 正弦(0)
====13操作数转换成功: 0 -> 0.0
====正弦结果: 0.0
====1词法分析器: input_str:0 余弦
====11 理单操作数函数predicate:余弦
====12执行单操作数函数: 余弦(0)
====13操作数转换成功: 0 -> 0.0
====余弦结果: 1.0
====1词法分析器: input_str:0 正切
====11 理单操作数函数predicate:正切
====12执行单操作数函数: 正切(0)
====13操作数转换成功: 0 -> 0.0
====正切结果: 0.0
..
----------------------------------------------------------------------      
Ran 3 tests in 0.006s

OK

代码部分是这样的:

    def lexer(self, input_str):
        """词法分析器"""
        tokens = []
        pos = 0
        print(f"====1词法分析器: input_str:{input_str}")
        
        while pos < len(input_str):
            # 跳过空白字符
            match = re.match(r'\s+', input_str[pos:])
            if match:
                pos += len(match.group())
                continue
                
            if pos >= len(input_str):
                break
                
            # 检查数字(优先检查数字,因为数学函数可能包含数字)
            # 原逻辑:match = re.match(self.token_types["number"], input_str[pos:])
            # 修改为:match = re.match(r'^[0-9]+(\.[0-9]+)?', input_str[pos:])
            match = re.match(r'^[0-9]+(\.[0-9]+)?', input_str[pos:])
            if match:
                token = match.group()
                tokens.append({"type": "number", "value": token})
                pos += len(token)
                continue
                
            # 检查关键字、操作符和分隔符
            found = False
            for token_type in ["keywords", "operators", "delimiters"]:
                for token in self.token_types[token_type]:
                    if input_str[pos:].startswith(token):
                        tokens.append({"type": token_type[:-1], "value": token})
                        pos += len(token)
                        found = True
                        break
                if found:
                    break
            if found:
                continue
                
            # 检查数学函数(如'开方'等)
            for op in self.token_types["operators"]:
                if input_str[pos:].startswith(op):
                    tokens.append({"type": "operator", "value": op})
                    pos += len(op)
                    found = True
                    break
            if found:
                continue
                
            # 检查标识符
            match = re.match(self.token_types["identifier"], input_str[pos:])
            if match:
                token = match.group()
                tokens.append({"type": "identifier", "value": token})
                pos += len(token)
                continue
            print(f"====2无法识别的字符: {input_str[pos]}")    
            raise Exception(f"无法识别的字符: {input_str[pos]}")
            
        return tokens

 

感慨与总结

国产AI,果然已经站到了第一集团,而且它不是一个人战斗,DeepSeek 、豆包、GLM乃至文心、千问等,正携手构建一个百花齐放、各具特色的创新生态,共同推动着中国AI技术走向世界前沿。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值