2009-12-04 3 views
2

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

редактировать: две гласные подряд означает такое же гласные (оо аа, б)

+0

Вы должны быть более ясными в отношении правила «двух гласных символов в строке» - предполагается, что оно применяется к «книгам», но не для «медведя». –

+0

Это как вытаскивание зубов - если два символа гласных не обязательно должны быть равными, какой появляется в замене? –

+0

Да, я имею в виду два двойных гласных подряд (ii, aa, oo) – roflwaffle

ответ

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

+0

Это хороший момент! Диспетчер - это таблица (предыдущих + текущих) пар символов. Subpair выполняет итерацию по строке, используя \ 0 для обозначения начала строки. Каждая пара просматривается в таблице отправки для замены. Если ничего не найдено, get возвращает текущий символ c. Алгоритм - линейная сложность - O (n). –

+0

Кроме того, как я мог заставить его делать и перед правилами? Итак, для 'na': u'ö ', измените' n 'на' ö 'вместо' a ' – roflwaffle

1

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

У меня есть строка в Юникоде в 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") 

EDIT: Теперь, когда я увидел ответ @Anon. Я думаю, что это самый простой подход. Это может быть быстрее, если вы получите целую кучу правил в игре, так как это делает один проход над строкой; но, возможно, нет, потому что регулярное выражение в Python является быстрым кодом C.

Но проще, лучше. Вот реальный код Python для подхода regexp:

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

+0

Вместо lst мы могли бы использовать строку. Но в Python строки неизменяемы, и мы не можем просто заменить последний символ; мы должны были бы сделать что-то вроде 's_new = s_new [: - 1] + new_ch'. Настоящая проблема заключается в том, что производительность действительно отстой. Добавление в список или замена элемента - это быстрая операция, но добавление к строке связано с копированием строки в новую строку и добавлением нового символа; это дает O (N ** 2) производительность, очень плохо. Последние версии Python оптимизировали этот конкретный случай, по крайней мере, некоторое время, но это традиционный способ сделать это. – steveha

+0

@steveha: ВНИМАНИЕ, вы тестируете последний символ вывода ('lst [-1]') вместо предыдущего символа ввода - в зависимости от того, что еще находится в полном наборе правил OP, это может быть хорошим идея или плохая идея. –

2

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

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

Вы могли бы написать один за правило, примерно так:

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

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

+0

Никогда не видел этот синтаксис в Python, какой модуль вы используете? – RedGlyph

+0

Этот синтаксис типичен для текстового редактора vi; он выражает идею, но не работает код Python. – steveha

+0

Это синтаксис Perl для регулярных выражений - замените знаки $ на обратную косую черту, чтобы получить синтаксис Python. –

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