代码之家  ›  专栏  ›  技术社区  ›  sisanared

用于名称标准化的python正则表达式

  •  2
  • sisanared  · 技术社区  · 8 年前

    我试图编写一个正则表达式来规范名称。

    用例:

    J. J. Abrams -> JJ Abrams
    J J Abrams -> JJ Abrams
    J.J Abrams -> JJ Abrams
    J.J. Abrams -> JJ Abrams
    J J  Abrams -> JJ Abrams (multiple spaces)
    

    缩写可以出现在名称的末尾或中间。通常,首字母可以在其前后有空格或“.”或单词边界。

    所以我提出了以下建议:

    p = re.compile(r'((\b|\s+|\.)[a-z](\.|\s+|\b))', re.I)
    

    当我试图匹配并打印结果时,它看起来是错误的:

    p.subn(lambda g: g.groups()[0].strip().strip('.'), "J J Abrams")
    ('JJAbrams', 2)
    

    如何保留非初始部分之前(或之后)的空间?

    编辑 而且,我应该说得很清楚,名字中可以有两个以上的首字母。以上只是一个随机用例。谢谢

    5 回复  |  直到 8 年前
        1
  •  3
  •   SamWhan    8 年前

    对于给定的情况,替换

    (?<=\b[A-Z]\b)[. ]+(?=[A-Z]\b)|\.|(\s)\s+
    

    具有

    $1
    

    应该这么做。

    它匹配,使用交替,空间和点之间的缩写,点任何地方或一个以上的空间。后者占据了第一个空间。

    替换为 $1 从前两个替换项中删除匹配项,在第三种情况下(多个空格)用单个替换项(捕获的第一个空格)。

    See it here at regex101 .

        2
  •  1
  •   Allan    8 年前

    我认为您可以通过使用regex分两步完成:

    步骤1:

    正则表达式:

     +|\. *
    

    和替换 (一个空格)

    step 1 demo

    步骤2:

    正则表达式:

    \b([a-z]) ([a-z])\b
    

    替换: \1\2

    step 2 demo

    把你拥有的一切结合起来:

    输入文件:

    $ cat names
    J. J. Abrams
    J J Abrams
    J.J Abrams
    J.J. Abrams
    J J  Abrams
    J  Abrams J.
    Abrams J. J.
    Abrams J J
    

    Python代码:

    $ cat names_norm.py 
    import re
    import sys
    
    with open("names") as file:
            for line in file:
                    line = re.sub(r" +|\. *", " ", line)
                    line = re.sub(r"\b([a-zA-Z]) ([a-zA-Z])\b", "\g<1>\g<2>", line)
                    sys.stdout.write(line)
    sys.stdout.flush()
    

    输出:

    $ python names_norm.py                                                                                                           
    JJ Abrams
    JJ Abrams
    JJ Abrams
    JJ Abrams
    JJ Abrams
    J Abrams J 
    Abrams JJ 
    Abrams JJ
    
        3
  •  0
  •   Austin    8 年前

    用途:

    re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
    

    代码 :

    >>> s = 'J. J. Abrams'
    >>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
    JJ Abrams
    
    >>> s = 'J J Abrams'
    >>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
    JJ Abrams
    
    >>> s = 'J.J Abrams'
    >>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
    JJ Abrams
    
    >>> s = 'J.J.  Abrams'
    >>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
    JJ Abrams
    
    >>> s = 'J J      Abrams'
    >>> re.sub(r'(?<!\w)([A-Z])\.*\s*(?<!\w)([A-Z])\.*\s*([A-Za-z]*)', r'\1\2 \3', s)
    JJ Abrams
    
        4
  •  0
  •   NeverHopeless    8 年前

    您可以尝试查找所有连续的字母表并使用以下格式打印:

    import re
    if __name__=='__main__': 
        names = ["J. J. Abrams", "J J Abrams", "J.J Abrams", "J.J. Abrams", "J J  Abrams", "J J J  Abrams"]
        for name in names:
            res = re.findall("([a-z]+)", name, re.I)       #Find all continuous alphabets
            res.insert(len(res)-1, " ").                   #Insert <space> at second last position 
            print("res : %s" % ("".join(map(str, res))))   #Join and display list which is formatted
    

    结果:

    res : JJ Abrams
    res : JJ Abrams
    res : JJ Abrams
    res : JJ Abrams
    res : JJ Abrams
    res : JJJ Abrams
    
        5
  •  0
  •   Sven Krüger    8 年前

    因为您只想过滤掉“.”和某些位置的空白,所以我建议您只使用标准字符串方法。

    1. 用一个空格替换所有点字符。
    2. 迭代所有由空格分隔的子字符串-每个被剥离 从前导空格和尾随空格
    3. 在长度超过一个字符的元素中添加一个前导空格和一个尾随空格。
    4. 把零件重新组装起来,不要留空隙。
    5. 从前导和尾随空格字符中删除整个字符串。

    为了你的高兴,我把它写成了一个完全不可读的单行本。

    names = ['J. R. R. Tolkien',  # "." and " "
             'Abrams  J J',       # " "
             'J.J Abrams',        # "." inbetween
             'J.R.R. Tolkien',    # "."
             'J R.R Tolkien']     # mixed
    
    for name in names :
        name = "".join([(" {} ".format(elem)) if len(elem)>1 else elem for elem in name.replace('.', ' ').split()]).strip()
    
        print name
    

    这就产生了这个输出。

    JRR Tolkien
    Abrams JJ
    JJ Abrams
    JRR Tolkien
    JRR Tolkien
    

    编辑

    @clasg的解决方案可能也不可读。但我的解决方案甚至需要两倍的计算时间。

    Elapsed time, mean value: 6.92432632016e-06
    Elapsed time, mean value: 1.5598555044e-05