Python:高效的多字符串替换

时间:2015-03-08 12:08:43

标签: python replace soundex

这项功能可以提高效率吗?我需要处理一百万个名字......

def indian_soundex_encode(s):
    s = s.replace("aa", "a")
    s = s.replace("ee", "i")
    s = s.replace("zh", "l")
    s = s.replace("oo", "u")
    s = s.replace("bu", "b")
    s = s.replace("dh", "d")
    s = s.replace("gh", "g")
    s = s.replace("jh", "j")
    s = s.replace("kh", "k")
    s = s.replace("sh", "s")
    s = s.replace("th", "t")
    s = s.replace("ck", "k")
    s = s.replace("kk", "k")
    s = s.replace("nn", "n")
    s = s.replace("mm", "m")
    s = s.replace("pp", "p")
    s = s.replace("ll", "l")
    s = s.replace("ty", "ti")
    s = s.replace("ot", "od")
    s = s.replace("iya", "ia")
    s = s.replace("ya", "ia")
    s = s.replace("sv", "s")
    s = s.replace("sw", "s")
    s = s.replace("my", "mi")
    return s

1 个答案:

答案 0 :(得分:3)

使用纯Python很难使函数更有效。 str.replace已经相当高效,但它需要多次扫描字符串,至少在某些情况下,会创建几个新字符串。使用仅扫描字符串一次的更智能算法替换对replace的多个调用,可能会使函数变慢,因为您在纯Python中执行更多工作并放弃{{1}的原始效率}。

如果在您的情况下可以编写C扩展模块,我建议您这样做。使用str.replace进行测量,对于样本字符串timeit,以下函数优于原始函数~17(0.184 usec,而Python版本为3.28 usec)。

"foobaaar"

使用PyObject * indian_soundex_encode(PyObject *ignore, PyObject *args) { PyObject *py_s, *py_ret; bool replaced = false; if (!PyArg_ParseTuple(args, "S", &py_s)) return NULL; const char *s = PyString_AS_STRING(py_s); Py_ssize_t len = PyString_GET_SIZE(py_s); char *ret = malloc(len + 1), *retptr = ret; if (!ret) return PyErr_NoMemory(); while (len > 0) { #define REPLACE(first, second, replacement) \ if (*s == first && *(s + 1) == second) { \ s += 2; \ len -= 2; \ *retptr++ = replacement; \ replaced = true; \ continue; \ } REPLACE('a', 'a', 'a'); REPLACE('e', 'e', 'i'); REPLACE('z', 'h', 'l'); REPLACE('o', 'o', 'u'); REPLACE('b', 'u', 'b'); REPLACE('d', 'h', 'd'); REPLACE('g', 'h', 'g'); REPLACE('j', 'h', 'j'); REPLACE('k', 'h', 'k'); REPLACE('s', 'h', 's'); REPLACE('t', 'h', 't'); REPLACE('c', 'k', 'k'); REPLACE('k', 'k', 'k'); REPLACE('n', 'n', 'n'); #undef REPLACE *retptr++ = *s++; --len; } if (!replaced) { py_ret = py_s; Py_INCREF(py_ret); } else py_ret = PyString_FromStringAndSize(ret, retptr - ret); free(ret); return py_ret; } 语句或者用C编码的更有效的查找表,可以进一步加快上述功能,但这仍然是读者的练习。

尝试在Cython中编写此函数的一个版本并将其性能与上面手写的C扩展进行比较将是另一个有趣的练习。

更新:上面的C函数对应于问题中的原始Python代码。编辑Jost在一个主要的代码更改中随着格式更改in his edit而偷偷摸摸,这显然没有被审阅者发现。