2009-12-04 50 views
2

我在Python中有一个unicode字符串,基本上需要经过一个字符的逐个字符并根据规则列表替换某些字符串。一个这样的规则是如果an之后a改为ö。另外,如果一行中有两个元音字符,它们将被一个元音字符和:取代。所以,如果我有字符串"natarook",获取"nötaro:k"最简单和最有效的方法是什么?如果有问题的话,使用Python 2.6和CherryPy 3.1。如何在字符串中进行有条件的字符替换

编辑:连续两个元音并不意味着同样的元音(OO,AA,II)

+0

您需要更清楚地了解您的“连续两个元音字符”规则 - 一个假设它适用于“book”,但不适用于“bear”。 – 2009-12-04 20:32:41

+0

这就像拔牙 - 如果两个元音字符不需要相同,哪一个出现在替换中? – 2009-12-05 00:44:16

+0

是的,我的意思是连续两个双元音(ii,aa,oo) – roflwaffle 2009-12-05 06:57:23

回答

7
# -*- coding: utf-8 -*- 

def subpairs(s, prefix, suffix): 
    def sub(i, sentinal=object()): 
     r = prefix.get(s[i:i+2], sentinal) 
     if r is not sentinal: return r 

     r = suffix.get(s[i-1:i+1], sentinal) 
     if r is not sentinal: return r 
     return s[i] 

    s = '\0'+s+'\0' 
    return ''.join(sub(i) for i in xrange(1,len(s))) 

vowels = [(v+v, u':') for v in 'aeiou'] 

prefix = {} 
suffix = {'na':u'ö'} 
suffix.update(vowels) 
print subpairs('natarook', prefix, suffix) 
# prints: nötaro:k 

prefix = {'na':u'ö'} 
suffix = dict(vowels) 
print subpairs('natarook', prefix, suffix) 
# prints: öataro:k 
+1

这是一个原始的想法,但也许你想要将其解释为OP ;-) – RedGlyph 2009-12-04 20:10:35

+0

这是一个好点! Dispatch是(previous + current)字符对的表格。子对使用\ 0对字符串进行成对迭代以表示字符串开始。每个配对都在配送表中查找替代使用。如果没有发现,get返回当前字符“c”。算法是线性复杂度 - O(n)。 – 2009-12-04 20:22:35

+0

另外,我怎样才能在规则之前做到这一点?因此,对于'na':u'ö',将'n'改为'ö'而不是'a' – roflwaffle 2009-12-07 15:15:02

1

鉴于你的规则,我说你真的想要一个简单的状态机。嗯,第二个想法,也许不是;你可以随时回头看看字符串。

我在Python中有一个unicode字符串,基本上需要逐个字符地逐个字符,并根据规则列表替换某些字符串。一个这样的规则是,如果a在n之后,则a被改变为ö。另外,如果一行中有两个元音字符,它们将被一个元音字符和:替换。所以如果我有字符串,获取“nötaro:k”最简单和最有效的方法是什么?如果有问题的话,使用Python 2.6和CherryPy 3.1。

vowel_set = frozenset(['a', 'e', 'i', 'o', 'u', 'ö']) 

def fix_the_string(s): 
    lst = [] 
    for i, ch in enumerate(s): 
     if ch == 'a' and lst and lst[-1] == 'n': 
      lst.append('ö') 
     else if ch in vowel_set and lst and lst[-1] in vowel_set: 
      lst[-1] = 'a' # "replaced by one vowel character", not sure what you want 
      lst.append(':') 
     else 
      lst.append(ch) 
    return "".join(lst) 

print fix_the_string("natarook") 

编辑:现在,我看到@Anon的答案。我认为这是最简单的方法。一旦你获得了大量的规则,这实际上可能会更快,因为它会传递一个字符串;但可能不会,因为Python中的正则表达式是快速的C代码。

但是越简单越好。下面是正则表达式的方法实际的Python代码:“我知道,我将使用正则表达式”

import re 
pat_na = re.compile(r'na') 
pat_double_vowel = re.compile(r'([aeiou])[aeiou]') 

def fix_the_string(s): 
    s = re.sub(pat_na, r'nö', s) 
    s = re.sub(pat_double_vowel, r'\1:', s) 
    return s 

print fix_the_string("natarook") # prints "nötaro:k" 
+0

不能'lst'只是一个字符串? – RedGlyph 2009-12-04 20:12:49

+0

而不是我们可以使用一个字符串。但字符串在Python中是不可变的,我们不能只替换最后一个字符;我们必须做一些事情,比如's_new = s_new [: - 1] + new_ch'。真正的问题是性能真的很糟糕。附加到列表或替换元素是一种快速操作,但追加到字符串涉及将字符串复制到新字符串,然后添加新字符;这给了O(N ** 2)的表现,非常糟糕。最近的Python版本已经优化了这个特定的情况,至少在某些时候,但这是实现它的传统方式。 – steveha 2009-12-04 20:21:22

+0

@steveha:小心,你正在测试对最后输出的字符('LST [-1]'),而不是对以前输入的字符 - 这取决于还有什么是在OP的全套规则,这可能是一个很好的想法或一个坏主意。 – 2009-12-04 20:42:31

2

但严重的是,正则表达式对于字符串操作确实很好。

你可以写每一个规则,像这样:

s/na/nö/g 
s/([aeiou])$1/$1:/g 

或者你也可以在运行时从其中列出了他们所有其他来源产生它们。

+0

从来没有在Python中看到过这种语法,您正在使用哪个模块? – RedGlyph 2009-12-04 20:09:39

+0

该语法是vi文本编辑器的典型代码;它表达了这个想法,但它并不适用于Python代码。 – steveha 2009-12-04 20:22:03

+0

这是用于正则表达式的Perl语法 - 用反斜杠替换$符号以获取Python语法。 – 2009-12-04 20:22:20

2

专注于容易正确首先,然后考虑效率,如果分析表明其瓶颈。

简单的方法是:

prev = None 
for ch in string: 
    if ch == 'a': 
    if prev == 'n': 
     ... 
    prev = ch 
1

这可能是简单的做用正则表达式的手工制作的列表,而不是progmatically gererating他们。我推荐以下代码。

import re 
# regsubs is a dictionary of regular expressions as keys, 
# and the replacement regexps as values 
regsubs = {'na':u'nö', 
      '([aeiou])\\1': '\\1:'} 

def makesubs(s): 
    for pattern, repl in regsubs.iteritems(): 
     s = re.sub(pattern, repl, s) 
    return s 

print makesubs('natarook') 
# prints: nötaro:k