2

在以下情况下,我想匹配字符串“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
4

5 回答 5

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")

如果它看起来更具可读性。

于 2013-02-25T16:23:38.127 回答
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...

RE的丑陋纯粹是内部的。

于 2013-02-25T17:33:31.310 回答
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))
于 2013-03-04T17:42:51.793 回答
1

有趣的是

/((S)((?i)ingapore))/

在 perl 中做正确的事,但在 python 中似乎没有按需要工作。公平地说,python 文档清楚地说明了它, (?i) 改变了整个正则表达式

于 2013-02-25T17:33:53.283 回答
0

这是最好的答案:

(?-i:S)(?i)ingapore

点击这里为证:

于 2019-11-15T04:03:35.850 回答