如何反向正则替换?

1 投票
3 回答
1622 浏览
提问于 2025-04-17 17:46

回到这个例子,

在Python中使用正则表达式处理相似字符以打印不同内容时遇到问题

我在想,我该如何把我做的正则替换反过来,直接打印出原来的文本呢?

也就是说,如果我有

text = "This is my first regex python example yahooa yahoouuee bbbiirdd"

作为我的原始文本,那么它的输出会是:

re.sub text = "tookhookisook isook mookyook fookirooksooktook pookyooktookhookonook..."

然后我想把这个输出再转换回原来的文本。

我该怎么做呢?

3 个回答

0

在Python或者其他正则表达式的工具中,你不能把正则替换的过程“反向转换”。

这是因为替换是单向的,就像一条单行道,只会返回一个新的字符串,没有什么神奇的反向功能。

下面用string.replace()来举个例子:

original_string = 'abc'
newstring = original_string.replace('a','b')
'bbc'

把新字符串变成'abc',并不是简单地把'a'替换成'b'。你不能从任何给定的正则表达式中创建一个“反向”的正则表达式。如果在这个例子中把'b'替换成'a',结果会是'aac',而不是'bbc'。

正则表达式的功能和string.replace()是一样的——它们都会返回一个新的字符串。它们并不会返回一个知道每次替换具体状态的对象。

如果你想做你想做的事情,有两个选择:

1- 创建一个自定义的类,代表一个字符串,并跟踪无限数量的正则表达式操作,这样你就可以在每个状态之间进行比较。

2- 跟大家一样,很多人也建议的做法:你只需要把原始字符串(或者它的副本)放到一边保存起来。

(这是为了简化@StoryTeller的回答)

4

Python中的字符串是不可变的。这意味着你并没有真正去“改变”原来的字符串,而是创建了一个新的字符串。你只需要保留对原字符串的引用。

补充说明
这里说的不可变,意思是字符串一旦创建,它的实际内容就不会再改变了。

>>> s = "abc"
>>> s[0]
'a'
>>> s[1] = 'd'

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    s[1] = 'd'
TypeError: 'str' object does not support item assignment
>>> 

在上面的例子中,我可以让变量 s 指向另一个对象,但我赋值给它的字符串是固定的。所以当你使用 s.replace() 时,得到的结果是一个新的字符串,而原来的字符串并没有被改变。

>>> s.replace ('a', 'd')
'dbc'
>>> s
'abc'
>>> 
1

看起来这个方法有效:

import re 

tu = ('This is my first regex python example '
      'yahooa yahoouuee bbbiirdd',

      'bbbiirdd',

      'fookirooksooktook',

      'crrsciencezxxxxxscienceokjjsciencq')

reg   = re.compile(r'([bcdfghj-np-tv-z])(\1?)')
dereg = re.compile('science([^aeiou])|([^aeiou])ook')

def Frepl(ma):
    g1,g2 = ma.groups()
    if g2:  return 'science' + g2
    else:   return g1 + 'ook'

def Fderepl(ma):
    g = ma.group(2)
    if g:  return g
    else:  return 2*ma.group(1)

for strt in tu:
    resu =   reg.sub(Frepl  , strt)
    bakk = dereg.sub(Fderepl, resu)
    print ('----------------------------------\n'
           'strt = %s\n'    'resu == %s\n'
           'bakk == %s\n'   'bakk == start : %s'
           % (strt, resu, bakk, bakk==strt))

编辑

首先,我更新了上面的代码:我去掉了 re.I 这个标志。之前这个标志会把像 'dD' 这样的部分当作重复字母来处理,所以它会变成 'scienceD',然后又变回 'DD'。

其次,我在代码中加入了一个字典。
它不是简单地把一个字母替换成字母+'ook',而是根据字母来进行替换。
比如,我选择把 'b' 替换成 'BAR',把 'c' 替换成 'CORE'……我把字典里的值都用大写字母写出来,这样结果看起来更清晰。其实可以用其他任何值。
程序会处理字母的大小写。我只在字典里放了 'T'、'Y'、'X',这只是为了测试。

import re 

d = {'b':'BAR','c':'CORE','d':'DEAD','f':'FAN',
     'g':'GO','h':'HHH','j':'JIU','k':'KOAN',
     'l':'LOW','m':'MY','n':'NERD','p':'PI',
     'q':'QIM','r':'ROAR','s':'SING','t':'TIP',
     'v':'VIEW','w':'WAVE','x':'XOR',
     'y':'YEAR','z':'ZOO',
     'T':'tears','Y':'yearling','X':'xylophone'}

ded = dict((v,k) for k,v in d.iteritems())
print ded

tu = ('This is my first regex python example '
       'Yahooa yahoouuee bbbiirdd',

      'bbbiirdd',

      'fookirooksooktook',

      'crrsciencezxxxxxXscienceokjjsciencq')

reg   = re.compile(r'([bcdfghj-np-tv-zBCDFGHJ-NP-TV-Z])(\1?)')

othergr = '|'.join(ded.keys())
dereg = re.compile('science([^aeiouAEIOU])|(%s)' % othergr)

def Frepl(ma, d=d):
    g1,g2 = ma.groups()
    if g2:  return 'science' + g2
    else:   return d[g1]

def Fderepl(ma,ded=ded):
    g = ma.group(2)
    if g:  return ded[g]
    else:  return 2*ma.group(1)

for strt in tu:
    resu =   reg.sub(Frepl  , strt)
    bakk = dereg.sub(Fderepl, resu)
    print ('----------------------------------\n'
           'strt = %s\n'    'resu == %s\n'
           'bakk == %s\n'   'bakk == start : %s'
           % (strt, resu, bakk, bakk==strt))

结果

----------------------------------
strt = This is my first regex python example Yahooa yahoouuee bbbiirdd
resu == tearsHHHiSING iSING MYYEAR FANiROARSINGTIP ROAReGOeXOR PIYEARTIPHHHoNERD eXORaMYPILOWe yearlingaHHHooa YEARaHHHoouuee sciencebBARiiROARscienced
bakk == This is my first regex python example Yahooa yahoouuee bbbiirdd
bakk == start : True
----------------------------------
strt = bbbiirdd
resu == sciencebBARiiROARscienced
bakk == bbbiirdd
bakk == start : True
----------------------------------
strt = fookirooksooktook
resu == FANooKOANiROARooKOANSINGooKOANTIPooKOAN
bakk == fookirooksooktook
bakk == start : True
----------------------------------
strt = crrsciencezxxxxxXscienceokjjsciencq
resu == COREsciencerSINGCOREieNERDCOREeZOOsciencexsciencexXORxylophoneSINGCOREieNERDCOREeoKOANsciencejSINGCOREieNERDCOREQIM
bakk == crrsciencezxxxxxXscienceokjjsciencq
bakk == start : True

撰写回答