如何重写字符串的遍历方法?

2018-06-14 15:07:38 +08:00
 Morriaty

默认的遍历方式是

for i in "为了让大家在 V2EX 上的时间更有效率":
     yield i

['为', '了', '让', '大', '家', '在', ' ', 'V', '2', 'E', 'X', ' ', '上', '的', '时', '间', '更', '有', '效', '率']

但现在希望的方式是遇见连续的英文数字就合并

for i in "为了让大家在 V2EX 上的时间更有效率":
     yield i

['为', '了', '让', '大', '家', '在', ' ', 'V2EX', ' ', '上', '的', '时', '间', '更', '有', '效', '率']

当然,最简单的方式是写一个foreach函数,然后for i in foreach(string)

只是想确认下是否可以直接重写字符串的遍历方法

3854 次点击
所在节点    Python
21 条回复
shuianfendi6
2018-06-14 15:50:55 +08:00
re.compile("[a-zA-Z0-9]+|[^\x00-\xff]").findall(a)
changrui0608
2018-06-14 18:50:19 +08:00
感觉可以自定义一个类继承 str,然后自己重写相应的方法
https://stackoverflow.com/questions/2673651/inheritance-from-str-or-int
F1024
2018-06-14 19:06:08 +08:00
"为了让大家在 V2EX 上的时间更有效率".split("")
linxiaoziruo
2018-06-14 19:44:53 +08:00
题主头像是谁
wangyongbo
2018-06-14 20:04:32 +08:00
for x in re.findall('[^A-Za-z\d]{1}|[A-Za-z\d]+', s):
... print x
crb912
2018-06-14 20:52:58 +08:00
Cpython 的字符串遍历,默认用了 yield 关键字?
polythene
2018-06-14 20:56:37 +08:00
@crb912 好像是用了 iterator 协议
crb912
2018-06-14 21:39:16 +08:00
@polythene yield 关键字,会让函数成为生成器 generator。
不同点是,1. 生成器只能被迭代一次,迭代器 iterator 没有这种限制,2. 而且生成器的元素不会一次读入内存,而是会在调用逐个加载。它们的共同点都实现了可迭代协议__iter__方法,__next__方法。
所以 yield 应该是你随手写的吧?
ccsiyu
2018-06-14 22:35:42 +08:00
写一个两层循环,在内层循环里用贪心法向前搜索能合并的单词

实际上还是 O(n)
Morriaty
2018-06-14 23:59:21 +08:00
@changrui0608 是不是我表述的太差了,貌似只有你一个人理解了我的意思
不过 SO 这个依然很麻烦,我必须修改所有的 str 赋值语句
a = "xxx"
改成
a = MyStr("xxx")
Morriaty
2018-06-15 00:00:23 +08:00
@linxiaoziruo 长泽雅美
Morriaty
2018-06-15 00:11:29 +08:00
@shuianfendi6 @wangyongbo @ccsiyu 你们误会我意思了,详见 append
ccsiyu
2018-06-15 02:10:00 +08:00
@Morriaty 知道了,你知道算法,但是想 override 原来的方法。那就用一个子类继承 str 这个父类(不熟悉 python,根据上下文猜测的)然后 override 就行了
XYxe
2018-06-15 03:08:48 +08:00
```python
import cffi
import ctypes


class new_str_iterator():
def __init__(self, s):
self.index = 0
self.s = s

def __iter__(self):
return self

def __next__(self):
'''你需要的功能'''


def __new_str_iter__(obj_addr):
obj = ctypes.cast(obj_addr, ctypes.py_object).value
iter_obj = new_str_iterator(obj)
ctypes.pythonapi.Py_IncRef(id(iter_obj))
return id(iter_obj)


ctypes.pythonapi.Py_IncRef.argtypes = [ctypes.c_size_t]
ITER_FUNC = ctypes.CFUNCTYPE(ctypes.c_ssize_t, ctypes.c_ssize_t)
cnew_str_iter = ITER_FUNC(__new_str_iter__)

ffi = cffi.FFI()
tp_iter_pointer = ffi.cast("size_t *", id(str) + 216)
tp_iter_pointer[0] = ctypes.cast(cnew_str_iter, ctypes.c_void_p).value
```
XYxe
2018-06-15 03:13:50 +08:00
xiaket
2018-06-15 07:12:16 +08:00
根据 import this, 这种 magic 东西最好是显式的而不是隐式的, 所以推荐显式地定义 /import 一个类, 然后将你的逻辑放到这个类里面.
MrGba2z
2018-06-15 08:21:48 +08:00
class Vstr(str):
def __iter__(self):
special_set = 'abcdefghijklmnV2EX'
special_str = ''
for i in super().__iter__():
if i in special_set:
special_str += i
else:
if special_str:
yield special_str
special_str = ''
yield i


mystr = Vstr('为了让 abc 在 V2EX 上的 egg222 时间更有效率')
for i in mystr:
print(i)
araraloren
2018-06-15 09:16:18 +08:00
不是可以用 wrapper/decorator/装饰器么,获取原函数的返回值,自己处理然后返回,同#17

#!/usr/bin/perl6
# your code goes here

Str.^find_method("split").wrap(
----sub split(|c) {
--------my @x = callwith(|c); # call Str::split with all arguments
--------my @r = [];
--------my ($i, $j) = (0, 0);
--------my regex letter-number { <[a..z0..9]> }

--------for @x -> $x {
------------if $x.lc ~~ /<letter-number>/ && $i > 0 && @r[$i-1].lc ~~ /<letter-number>/ {
----------------@r[$i-1] ~= $x;
------------} else {
----------------@r[$i++] = $x;
------------}
--------}
--------@r;
----}
);

my $ms = "为了让大家在 V2EX 上的时间更有效率";

say $ms;

say $ms.split("").join("===");

https://ideone.com/FLlxXe
HaoC12
2018-06-15 10:54:55 +08:00
是不是可以通过栈来实现,判断进入的元素是不是字母,如果是在判断下一个,直到不是字母,出栈,下一个元素入栈。
excellentcx
2018-06-15 16:20:49 +08:00
难道不是正则表达式就可以完成的么???

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

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

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

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

© 2021 V2EX