万万没想到, Python 的字符串裁切函数居然还能有 bug

2022-12-21 19:54:53 +08:00
 WordTian

吐个槽,大家猜猜 python3 执行这 2 句话都会出现什么?

print('test.py'.rstrip(".py"))
print('testy.py'.rstrip(".py"))

这 2 句呢

print('test6y'.rstrip("6y"))
print('testy6y'.rstrip("6y"))
8380 次点击
所在节点    Python
51 条回复
snw
2022-12-22 09:43:19 +08:00
@snw
另外,Python 的文档里只提了省略参数则默认移除 whitespace 。但凡用过其他语言 trim 函数(哪怕是 Excel )的人都知道非显示字符有很多,常见的除了 ascii 第 32 个字符还有 、tab 等,不讲明根本就不知道移除的是哪个(些)。

连 Excel 的 TRIM 函数文档都会特别提示这一点:
https://support.microsoft.com/en-us/office/trim-function-410388fa-c5df-49c6-b16c-9e5630b479f9
snw
2022-12-22 09:50:18 +08:00
@NoAnyLove
因为你知道这函数用途了,再看这个文档就会觉得自然,反过来就很困难。总之对比一下其他语言的文档。
NoAnyLove
2022-12-22 10:24:22 +08:00
@snw #21 为啥会觉得 whitespace 不清楚,看看 wikipedia 就知道,

> In computer programming, whitespace is any character or series of characters that represent horizontal or vertical space in typography.

不清楚 whitespace 具体有哪些的话,查一下文档或者 Google 一下就行了。举个例子,如果有一个创建线程的 API 文档,旁边还专门给出线程的定义,这固然是好的,但是没有也没啥奇怪的。不能因为自己对某个概念不熟悉就觉得是文档做得不好啊。

#22 我第一次看这个文档的时候也没觉得有啥问题啊。如果要对比 php 的文档的话,感觉你困惑只是不清楚 whitespace 有哪些,而非 rstrip 是怎么工作的。
JeffGe
2022-12-22 10:31:28 +08:00
看标题就猜到是这个问题了,我觉得不管文档写得好不好,至少得先去看一下嘛
xuminzhong
2022-12-22 10:35:55 +08:00
哎,我也学艺不精,平时一直只是用无参来去空格和\n ,没试过多个字符组合,差点也掉坑里了。
liprais
2022-12-22 10:36:29 +08:00
人菜瘾大
wheeler
2022-12-22 10:40:41 +08:00
golang 是 trimleft 和 trimprefix ,直观吗?
xuyang2
2022-12-22 11:03:39 +08:00
@wheeler 我觉得还行

当然如果调用 API 之前,连两句话的 godoc 都懒得看,(其中一句还是介绍别的方法的)
我也不知道该说啥了

https://pkg.go.dev/strings#TrimLeft
func TrimLeft(s, cutset string) string

TrimLeft returns a slice of the string s with all leading Unicode code points contained in cutset removed.

To remove a prefix, use TrimPrefix instead.
lovelylain
2022-12-22 11:12:12 +08:00
@Jirajine 如果你用 c++
julyclyde
2022-12-22 11:17:00 +08:00
@lambdaq 即使语言设计者有责任
用语言写软件的那个程序员依然是软件质量的第一责任人
lovelylain
2022-12-22 11:17:44 +08:00
@Jirajine 如果你用 c++,想必也会用错 std::string::find_first_of/find_last_of 并坚持认为是 api 设计缺陷,而非自己不看文档瞎 jb 用的问题咯。
binxin
2022-12-22 11:20:32 +08:00
看完讨论,觉得 py 就这么定义的爱用不用。
看完文档中下面这个 case ,突然有点想说脏话。

'mississippi'.rstrip('ipz')
'mississ'
lambdaq
2022-12-22 12:10:57 +08:00
@krixaar 你好厉害哦。到 17 楼才参与讨论,大家差不多分队了就开始加入人多的地方并开始指责另外一方对线是吧?

好好讨论问题不行吗?非得搞饭圈哪一套?要不再来打打拳?

我觉得一个设计好的语言大部分的时候都是从内置方法名字就能看出其作用而不会被坑。我不觉得 rstrip 符合这个标准。你们觉得 rstrip 没问题,那何苦加入 removesuffix 这个新方法呢。

你们这么喜欢开地图炮,那么我也开个地图炮,为 rstrip 辩护的就是受虐狂和典型的东亚反思怪。做题家那种以能猜中出题人难题怪题为傲的沾沾自喜心思。https://peps.python.org/pep-0616/ 去看这 Rationale 明明这个东西坑了一大堆人。This repeated issue is evidence that these methods are useful. The new methods allow a cleaner redirection of users to the desired behavior

语言是拿来用的,不是拿来讲茴香豆几种写法区别的。rstrip 有他的使用场景、历史上有其合理性,不代表它占据这个容易混淆的名字 20 年被很多人误会就是服众的。

退万步说,不在 rstrip 文档里用 72px 红色加粗字体指出可能的坑就是对不起观众。
lambdaq
2022-12-22 12:35:02 +08:00
地图炮开完了,最后还是反思一下。我自己怎么踩坑的呢,当不知道有 strip rstrip lstrip 存在的时候,啥字符串方法都靠自己数下标去 slice 操作,后来看文档发现新世界,居然 py 字符串自带了这么多方法。于是就果断在能用的地方全部用内置方法。写起来真爽。。。rstrip 这玩意迷惑的一点还在于 80% 的字符串,其实能返回和 removesuffix 一样的结果。。。。你还以为你的姿势是正确的。。。直到你去跑野数据的字符串发现一个大循环内部报了个奇怪的错,费劲心思调试出来搞得怀疑人生。。。。

好了。你们可以喷我了。
krixaar
2022-12-22 15:46:49 +08:00
@lambdaq #33 因为如果 rstrip 这个方法确实做到了在文档里说明的作用,而使用者单纯根据这个方法的“名称”理解导致和文档不一致,这怎么能是“设计者的责任”?
换个例子,substr/substring/string.sub 这类看着就是截取字符串的函数,参数 start ,JS 等众多语言里从 0 开始,SQL 里从 1 开始,Oracle SQL 里 0 和 1 都算 1 ,这是 SQL“设计者的责任”?用错了难道不是该 RTFM ?

“他是错了,难道对方就没有责任吗”这种话整天看太多了,如果你不是这类话术表达的意思,我表示抱歉。如果你就是这个意思,那就我错了,你说的都对,GvR 罪大恶极,Python 语言好死不死用什么英文缩写做方法名,气抖冷!
lambdaq
2022-12-22 16:44:40 +08:00
@krixaar

对线的话就要对准;大概分三条线:

1. rstrip 单就它本身的引入目的和实现方式有没有设计缺陷?大家也说了,很多语言都这样,所以不算有缺陷
2. rstrip 作为 py 众多方便的 str 方法之一有没有迷惑性和误导性?我个人觉得有,而且算设计缺陷
3. 字符串操作方法相关的文档和说明有没有缺陷?我也觉得有问题。

你要对哪一条?还是要比划打拳?
krixaar
2022-12-22 17:06:24 +08:00
@lambdaq #36 正确的说“缺陷”方式直到你的回复还都没提到,这里我直接说了吧,rstrip 的问题在于这个 r:
1. rstrip 的“Right”并没有指出是字符串的“Right”还是方向的“Right”,即,是从字符串的“右侧”开始 strip ,还是从字符串的开头“向右”strip ,因为,从字符串“右侧”往回删除是“向左”删除。( StackOverflow 关于用反了的问题不止一个,这里举个例子: https://stackoverflow.com/questions/71667211/python-string-rstrip-doesnt-strip-specified-characters
2. 对于 RTL ( Right-to-Left ,从右向左的那些语言环境),此时的 R 和 L 对于这部分可能是土豪国家的程序员来说是不是具有迷惑性。
所以任何语言中对于 trim/strip 提到 L 和 R 的都有迷惑性,应该改为 Start/End ,例如 JS 还有 dotNet 中 trimStart 和 TrimEnd 这类,或者,就如同 Python 之后出现的 removesuffix 。

而不是讨论怎么“strip”和跟着的“参数”到底该是什么,讨论这个 L 和 R 啊亲们。
参数这就单纯是语言设计,Python 如果有设计者的责任,那也是强制缩进而不是一个破内置方法。

至于说这个方法有没有误导性,你只学 Python 这一门语言是没有误导性的,误导性和迷惑性的引入不还是因为有“很多其它语言”不是这样吗?
类比我之前的例子,这次扯远点,Lua/Matlab 的数组索引从 1 开始,设计缺陷还是语言 feature ?这比一个 rstrip 迷惑多了,整个和 offset/length 相关的地方都得考虑到底要不要+1 或者-1 了。
zedx7
2022-12-22 17:33:36 +08:00
@lambdaq 我觉得你可以提个 pr
lambdaq
2022-12-22 17:36:53 +08:00
@krixaar 所以你压根就不是来讨论问题的。。。。就是来搅着玩的。你说的这个问题,rstrip 是问题最严重的一个嘛? .zfill() 呢? .center() 这些对于非半角文字岂不是问题更多?你把注意力转移开,只能说你一开始想跑题。
krixaar
2022-12-22 17:54:13 +08:00
@lambdaq #39 从一开始讨论这个方法是不是“设计缺陷”就已经跑题了啊,楼主的问题已经解决,文档表述没有错误,不是 bug ,是 feature ,就可以结了啊,这不是有人给上升到“设计缺陷”了吗。
单一个 rstrip 这个方法的参数和行为和别的语言不同,只能说明它们是不同的语言,而不是这个语言的“设计缺陷”,不然所有的语言类似功能互相之间都是“设计缺陷”,如同 substring 的不同语言表现。
真正 rstrip 这个“方法名”的“设计缺陷”,就如同我上个回复,指的是 rstrip 这个名字本身,而不是使用者会“猜错它的参数”,本来就不该猜,也不能类比,按照每个语言的文档来。
我还没提重载这种同方法不同参数都能有不同功能的设计模式,这不更“设计缺陷”嘛。
还是我第一个回复,你让官方把 rstrip 的方法名给改得详细一些就完事了,“缺陷”就补上了,不用继续讨论了。
下班了下班了不回了,楼主看到一堆回复估计都懵了🤣。已 block ,请互 block 。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/903994

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX