Заменить в строке на основе функции

Итак, для ввода:

accessibility,random good bye 

Я хочу вывод:

 a11y,r4m g2d bye 

Поэтому, в основном, я должен сокращать все слова длины, большие или равные 4, в следующем формате: first_letter + length_of_all_letters_in_between + last_letter

Я пытаюсь сделать это:

 re.sub(r"([A-Za-z])([A-Za-z]{2,})([A-Za-z])", r"\1" + str(len(r"\2")) + r"\3", s) 

Но это не работает. В JS я бы легко сделал:

 str.replace(/([A-Za-z])([A-Za-z]{2,})([A-Za-z])/g, function(m, $1, $2, $3){ return $1 + $2.length + $3; }); 

Как мне сделать то же самое в Python?

EDIT: Я не могу позволить себе потерять какие-либо знаки препинания в оригинальной строке.

7 Solutions collect form web for “Заменить в строке на основе функции”

Проблема, с которой вы сталкиваетесь, заключается в том, что len(r'\2') всегда 2 , а не длина второй группы захвата в вашем регулярном выражении. Вы можете использовать выражение lambda для создания функции, которая работает так же, как код, который вы будете использовать в JavaScript:

 re.sub(r"([A-Za-z])([A-Za-z]{2,})([A-Za-z])", lambda m: m.group(1) + str(len(m.group(2)) + m.group(3), s) 

Аргумент m для лямбда является объектом соответствия, а вызовы его group методу эквивалентны обратным ссылкам, которые вы использовали ранее.

Может быть проще просто использовать простой шаблон совпадения слов без захвата групп ( group() все равно можно вызвать без аргумента, чтобы получить весь согласованный текст):

 re.sub(r'\w{4,}', lambda m: m.group()[0] + str(len(m.group())-2) + m.group()[-1], s) 

То, что вы делаете в JavaScript, конечно, правильно, вы передаете анонимную функцию. То, что вы делаете в Python, – это передать постоянное выражение («\ 12 \ 3», так как len(r"\2") оценивается перед вызовом функции), это не функция, которую можно оценить для каждого соответствия!

Хотя анонимные функции в Python не так полезны, как в JS, они выполняют эту работу здесь:

 >>> import re >>> re.sub(r"([A-Za-z])([A-Za-z]{2,})([A-Za-z])", lambda m: "{}{}{}".format(m.group(1), len(m.group(2)), m.group(3)), "accessability, random good bye") 'a11y, r4m g2d bye' 

Здесь происходит то, что лямбда вызывается для каждой подстановки, принимая объект соответствия. Затем я извлекаю необходимую информацию и строю из нее строку подстановки.

 tmp, out = "","" for ch in s: if ch.isspace() or ch in {",", "."}: out += "{}{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1], ch) if len(tmp) > 3 else tmp + ch tmp = "" else: tmp += ch out += "{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1]) if len(tmp) > 3 else tmp print(out) a11y,r4m g2d bye 

Если вам нужны только альфа-символы, используйте str.isalpha:

 tmp, out = "", "" for ch in s: if not ch.isalpha(): out += "{}{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1], ch) if len(tmp) > 3 else tmp + ch tmp = "" else: tmp += ch out += "{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1]) if len(tmp) > 3 else tmp print(out) a11y,r4m g2d bye 

Логика одинакова для обоих, это то, что мы проверяем на то, что отличается, если not ch.isalpha() False, мы обнаружили not ch.isalpha() символ, поэтому нам нужно обработать строку tmp и добавить ее к выходной строке. if len(tmp) не больше 3 согласно требованию, мы просто добавляем строку tmp плюс текущий символ в нашу строку.

Нам нужен финальный out += "{}{}{} вне цикла, чтобы поймать, когда строка не заканчивается запятой, пробелом и т. Д. Если строка закончилась не-альфой, мы добавили бы пустую строку так что это не имело бы никакого значения для выхода.

Он сохранит знаки препинания и пробелы:

  s = "accessibility,random good bye !! foobar?" def func(s): tmp, out = "", "" for ch in s: if not ch.isalpha(): out += "{}{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1], ch) if len(tmp) > 3 else tmp + ch tmp = "" else: tmp += ch return "{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1]) if len(tmp) > 3 else tmp print(func(s,3)) a11y,r4m g2d bye !! f4r? 

Будь проще…

 >>> s = "accessibility,random good bye" >>> re.sub(r'\B[A-Za-z]{2,}\B', lambda x: str(len(x.group())), s) 'a11y,r4m g2d bye' 

\B который соответствует двум символам слов или двум символам, отличным от слов, помогает совместить все символы, кроме первого и последнего.

В качестве альтернативного точного способа вы можете использовать отдельную функцию для re.sub и использовать простое регулярное выражение r"(\b[a-zA-Z]+\b)" .

 >>> def replacer(x): ... g=x.group(0) ... if len(g)>3: ... return '{}{}{}'.format(g[0],len(g)-2,g[-1]) ... else : ... return g ... >>> re.sub(r"(\b[a-zA-Z]+\b)", replacer, s) 'a11y,r4m g2d bye' 

Также как пифонический и общий способ, чтобы получить замененные слова в списке, вы можете использовать понимание списка с помощью re.finditer :

 >>> from operator import sub >>> rep=['{}{}{}'.format(i.group(0)[0],abs(sub(*i.span()))-2,i.group(0)[-1]) if len(i.group(0))>3 else i.group(0) for i in re.finditer(r'(\w+)',s)] >>> rep ['a11y', 'r4m', 'g2d', 'bye'] 

re.finditer вернет генератор, содержащий все matchobjects после чего вы можете перебрать его и получить начало и конец matchobject s с помощью метода span() .

Использование регулярного выражения и понимания:

 import re s = "accessibility,random good bye" print "".join(w[0]+str(len(w)-2)+w[-1] if len(w) > 3 else w for w in re.split("(\W)", s)) 

дает:

 a11y,r4m g2d bye 

Посмотрите следующий код

 sentence = "accessibility,random good bye" sentence = sentence.replace(',', " ") sentence_list = sentence.split(" ") for item in sentence_list: if len(item) >= 4: print item[0]+str(len(item[1:len(item)-1]))+item[len(item)-1] 

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

  • Регулярное выражение Python сопоставляет текст между кавычками
  • Python / Regex - Match. #, #. в String
  • Как проверить, была ли re.sub () успешно заменена на python?
  • Python Regex захватывает только определенный текст
  • Почему в Python существуют как sre, так и re-модули?
  • Используйте регулярные выражения для замены перекрывающихся подшаблонов
  • Соответствующие даты с регулярными выражениями в Python?
  • проанализировать с помощью регулярного выражения и распечатать строку
  •  
    Interesting Posts for Van-Lav

    Чтение в файле – изменение содержимого – запись в тот же файл

    Как передать элементы в цикл с помощью Jinja2 / Flask?

    Как сформировать анонимный запрос API API Imgur

    Применение граничных условий в конечно-разностном решении для уравнения теплопроводности и Крина-Николсона

    как импортировать __future__ для аргумента python 3.0 только для ключевого слова?

    Функции расширения и размытия Python-OpenCV не изменяют ничего

    Как загрузить файл с Python, Selenium и PhantomJS

    SSL: CERTIFICATE_VERIFY_FAILED] подтвержден сертификат

    Matplotlib: Пользовательская цветовая палитра с тремя цветами

    Поиск количества раз, когда подстрока существует в строке – Python

    Выделение массива типа SWIG C ++ из Python

    Есть ли понимание OrderedDict?

    Как открыть последовательный порт с помощью pyserial?

    Каков самый чистый способ вызова функции Python из C ++ с помощью SWIG Wrapped Object

    Есть ли эквивалент управления зависимостью maven / ivy для python?

    Python - лучший язык программирования в мире.