Python正则表达式(检查第一个字母区分大小写,其余不区分)

2 投票
5 回答
1613 浏览
提问于 2025-04-17 17:03

在下面的例子中,我想要找到字符串“Singapore”,其中“S”必须是大写的,而其他字母可以是小写或大写。但是在下面的字符串中,“s”是小写的,结果在搜索条件中也被匹配上了。有没有人能告诉我该怎么实现这个?

       import re       
            st = "Information in sinGapore "

            if re.search("S""(?i)(ingapore)" , st):
                print "matched"

Singapore => matched  
sIngapore => notmatched  
SinGapore => matched  
SINGAPORE => matched

5 个回答

2

你可以写一个简单的lambda函数来生成那个看起来很复杂但能解决问题的东西:

>>> leading_cap_re = lambda s: s[0].upper() + ''.join('[%s%s]' % 
                                                    (c.upper(),c.lower()) 
                                                        for c in s[1:])
>>> leading_cap_re("Singapore")
'S[Ii][Nn][Gg][Aa][Pp][Oo][Rr][Ee]'

对于包含多个单词的城市名,可以定义一个字符串分割的版本:

>>> leading_caps_re = lambda s : r'\s+'.join(map(leading_cap_re,s.split()))
>>> print leading_caps_re('Kuala Lumpur')
K[Uu][Aa][Ll][Aa]\s+L[Uu][Mm][Pp][Uu][Rr]

然后你的代码就可以变得很简单:

if re.search(leading_caps_re("Singapore") , st):
    ...etc...

这样复杂的部分就只是在内部处理了。

5

正如评论中提到的,比较难看的方法是:

>>> re.search("S[iI][Nn][Gg][Aa][Pp][Oo][Rr][Ee]" , "SingaPore")
<_sre.SRE_Match object at 0x10cea84a8>
>>> re.search("S[iI][Nn][Gg][Aa][Pp][Oo][Rr][Ee]" , "Information in sinGapore")

更优雅的方法是忽略大小写来匹配“新加坡”,然后检查第一个字母是否是 S

reg=re.compile("singapore", re.I)

>>> s="Information in sinGapore"
>>> reg.search(s) and reg.search(s).group()[0]=='S'
False

>>> s="Information in SinGapore"
>>> reg.search(s) and reg.search(s).group()[0]=='S'
True

更新

根据你的评论,你可以使用:

reg.search(s).group().startswith("S")

而不是:

reg.search(s).group()[0]==("S")

如果这样看起来更容易理解的话。

2

因为你想根据捕获到的短语(独特的名字或几个用空格分开的名字,我知道)来设置一个GV代码,所以必须有一步是根据捕获到的短语在字典中选择代码。
所以我们可以利用这一步来测试第一个字母(必须是大写)或者短语中的第一个名字,而这些是正则表达式无法做到的。

我选择了一些条件来进行测试。例如,第一个名字中是否有点(.)并不是必须的,但大写字母是必须的。这些条件可以根据需要轻松更改。

编辑 1

import re

def regexize(cntry):
    def doot(x):
        return '\.?'.join(ch for ch in x) + '\.?'
    to_join = []
    for c in cntry:
        cspl = c.split(' ',1)
        if len(cspl)==1: # 'Singapore','Austria',...
            to_join.append('(%s)%s'
                           % (doot(c[0]), doot(c[1:])))
        else: # 'Den LMM','LMM Den',....
            to_join.append('(%s) +%s'
                           % (doot(cspl[0]),
                              doot(cspl[1].strip(' ').lower())))
    pattern = '|'.join(to_join).join('()')
    return re.compile(pattern,re.I)

def code(X,CNTR,r = regexize):
    r = regexize(CNTR)
    for ma in r.finditer(X):
        beg = ma.group(1).split(' ')[0]
        if beg==ma.group(1):
            GV = countries[beg[0]+beg[1:].replace('.','').lower()] \
                 if beg[0].upper()==beg[0] else '- bad match -'
        else:
            try:
                k = (ki for ki in countries.iterkeys()
                     if beg.replace('.','')==ki.split(' ')[0]).next()
                GV = countries[k]
            except StopIteration:
                GV = '- bad match -'
        yield '  {!s:15}  {!s:^13}'.format(ma.group(1), GV)

countries = {'Singapore':'SG','Austria':'AU',
             'Swiss':'CH','Chile':'CL',
             'Den LMM':'DN','LMM Den':'LM'}

s = ('  Singapore  SIngapore  SiNgapore  SinGapore'
     '  SI.Ngapore  SIngaPore  SinGaporE  SinGAPore'
     '  SINGaporE  SiNg.aPoR   singapore  sIngapore'
     '  siNgapore  sinGapore  sINgap.ore  sIngaPore'
     '  sinGaporE  sinGAPore  sINGaporE  siNgaPoRe'
     '    Austria    Aus.trIA    aUSTria    AUSTRiA'
     '  Den L.M.M     Den   Lm.M    DEn Lm.M.'
     '  DEN L.MM      De.n L.M.M.     Den LmM'
     '    L.MM   DEn      LMM DeN     LM.m  Den')

print '\n'
print '\n'.join(res for res in code(s,countries))

编辑 2

我改进了代码。现在更简短、更易读。
指令 assert(.....] 是用来验证字典的键是否符合要求。

import re

def doot(x):
    return '\.?'.join(ch for ch in x) + '\.?'

def regexize(labels,doot=doot,
             wg2 = '(%s) *( %s)',wnog2 = '(%s)(%s)',
             ri = re.compile('(.(?!.*? )|[^ ]+)( ?) *(.+\Z)')):
    to_join = []
    modlabs = {}
    for K in labels.iterkeys():
        g1,g2,g3 = ri.match(K).groups()
        to_join.append((wg2 if g2 else wnog2)
                       % (doot(g1), doot(g3.lower())))
        modlabs[g1+g2+g3.lower()] = labels[K]
    return (re.compile('|'.join(to_join), re.I), modlabs)



def code(X,labels,regexize = regexize):
    reglab,modlabs = regexize(labels)
    for ma in reglab.finditer(X):
        a,b = tuple(x for x in ma.groups() if x)
        k = (a + b.lower()).replace('.','')
        GV = modlabs[k] if k in modlabs else '- bad match -'
        yield '  {!s:15}  {!s:^13}'.format(a+b, GV)

countries = {'Singapore':'SG','Austria':'AU',
             'Swiss':'CH','Chile':'CL',
             'Den LMM':'DN','LMM Den':'LM'}

assert(all('.' not in k and
          (k.count(' ')==1 or k[0].upper()==k[0])
          for k in countries))

s = ('  Singapore  SIngapore  SiNgapore  SinGapore'
     '  SI.Ngapore  SIngaPore  SinGaporE  SinGAPore'
     '  SINGaporE  SiNg.aPoR   singapore  sIngapore'
     '  siNgapore  sinGapore  sINgap.ore  sIngaPore'
     '  sinGaporE  sinGAPore  sINGaporE  siNgaPoRe'
     '    Austria    Aus.trIA    aUSTria    AUSTRiA'
     '  Den L.M.M     Den   Lm.M    DEn Lm.M.'
     '  DEN L.MM      De.n L.M.M.     Den LmM'
     '    L.MM   DEn      LMM DeN     LM.m  Den')

print '\n'.join(res for res in code(s,countries))

撰写回答