Как сделать условную замену символа в строке - PullRequest
2 голосов
/ 04 декабря 2009

У меня есть строка в кодировке Unicode в Python, и в основном мне нужно пройти, символ за символом, и заменить некоторые из них на основе списка правил. Одним из таких правил является то, что a изменяется на ö, если a после n. Также, если в строке два гласных символа, они заменяются одним гласным символом и :. Итак, если у меня есть строка "natarook", какой самый простой и эффективный способ получить "nötaro:k"? Использование Python 2.6 и CherryPy 3.1, если это имеет значение.

edit: две гласные подряд означают одинаковые гласные (oo, aa, ii)

Ответы [ 5 ]

7 голосов
/ 04 декабря 2009
# -*- 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
2 голосов
/ 04 декабря 2009

«Я знаю, я буду использовать регулярные выражения!»

А если серьезно, регулярные выражения действительно хороши для работы со строками.

Вы можете написать по одному на правило, например:

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

Или вы можете сгенерировать их во время выполнения из другого источника, в котором перечислены все.

2 голосов
/ 04 декабря 2009

Сначала сосредоточьтесь на easy и правильный , затем рассмотрите эффективность, если профилирование указывает на узкое место.

Простой подход:

prev = None
for ch in string:
  if ch == 'a':
    if prev == 'n':
      ...
  prev = ch
1 голос
/ 04 декабря 2009

Возможно, было бы проще сделать список регулярных выражений, составленный вручную, а не создавать их с помощью программной обработки. Я рекомендую следующий код.

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
1 голос
/ 04 декабря 2009

Учитывая ваши правила, я бы сказал, что вы действительно хотите простой конечный автомат. Хм, если подумать, может и нет; вы можете просто оглянуться назад в строку, как вы идете.

У меня есть строка в кодировке Unicode в Python, и в основном мне нужно пройти, символ за символом, и заменить некоторые из них на основе списка правил. Одно из таких правил состоит в том, что a меняется на ö, если a следует за n. Кроме того, если в строке два гласных символа, они заменяются одним гласным символом и:. Итак, если у меня есть строка, какой самый простой и эффективный способ получить «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"
...