所以,输入:
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中做同样的事情?
编辑:我不能丢失原始字符串中的任何标点符号。
答案 0 :(得分:7)
你在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'
这里发生的是为每个替换调用lambda,获取匹配对象。然后,我检索所需的信息并从中构建替换字符串。
答案 1 :(得分:3)
您遇到的问题是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)
lambda的m
参数是match
对象,对group
方法的调用等同于之前使用的反向引用。
使用简单的单词匹配模式而不使用捕获组可能更容易(group()
仍然可以在没有参数的情况下调用以获取整个匹配的文本):
re.sub(r'\w{4,}', lambda m: m.group()[0] + str(len(m.group())-2) + m.group()[-1], s)
答案 2 :(得分:2)
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我们发现了一个非alpha字符,所以我们需要处理tmp字符串并将其添加到输出字符串。根据要求,if len(tmp)
不大于3
我们只需将tmp字符串加上当前字符添加到我们的输出字符串中。
我们需要循环外的最后out += "{}{}{}
来捕获字符串不以逗号,空格等结尾的时候。如果字符串以非alpha结尾,我们将添加一个空字符串,以便它对输出没什么影响。
它会保留标点符号和空格:
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?
答案 3 :(得分:1)
作为另一种精确方式,您可以为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'
同样作为pythonic和一般方式,要在列表中获取替换的单词,您可以使用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
的生成器,然后您可以迭代它并使用span()
方法获取matchobject
s的开头和结尾。
答案 4 :(得分:1)
保持简单......
>>> 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
有助于匹配除第一个和最后一个之外的所有字符。
答案 5 :(得分:0)
使用正则表达式和理解:
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
答案 6 :(得分:-1)
查看以下代码
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]
你唯一应该照顾逗号和其他标点字符。