【问题标题】:Python, remove all non-alphabet chars from stringPython,从字符串中删除所有非字母字符
【发布时间】:2014-04-26 14:06:01
【问题描述】:

我正在编写一个 python MapReduce 字数统计程序。问题是数据中散布着许多非字母字符,我发现这篇文章Stripping everything but alphanumeric chars from a string in Python 显示了使用正则表达式的一个很好的解决方案,但我不知道如何实现它

def mapfn(k, v):
    print v
    import re, string 
    pattern = re.compile('[\W_]+')
    v = pattern.match(v)
    print v
    for w in v.split():
        yield w, 1

恐怕我不确定如何使用库re 甚至是正则表达式。我不确定如何将正则表达式模式正确应用到传入字符串(书的行)v 以检索没有任何非字母数字字符的新行。

建议?

【问题讨论】:

  • v 是一本书的整行(特别是白鲸),我将逐字逐句地阅读。所以有些词的结尾可能有一个“,”,所以“indignity”不会与“indignity”对应。
  • Lolx - 你有和我一样的面试前家庭练习吗?在 Moby Dick 中找到 50 个最常用的词并报告它们的频率。我是用 C++ 做的,IIRC
  • @Mawg 这是我本科“云计算”课上的一个练习。

标签: python regex


【解决方案1】:

如果您计划匹配特定的 Unicode 属性类,建议使用 PyPi regex module。这个库也被证明更稳定,尤其是处理大文本,并且在各种 Python 版本中产生一致的结果。您需要做的就是使其保持最新状态。

如果你安装它(使用pip install regexpip3 install regex),你可以使用

import regex
print ( regex.sub(r'\P{L}+', '', 'ABCŁąć1-2!Абв3§4“5def”') )
// => ABCŁąćАбвdef

text 中删除所有包含 1 个或多个字符的块,而不是 Unicode 字母。请参阅online Python demo。您也可以使用"".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”')) 来获得相同的结果。

在 Python re 中,为了匹配任何 Unicode 字母,可以使用 [^\W\d_] 构造 (Match any unicode letter?)。

因此,要删除所有非字母字符,您可以匹配所有字母并加入结果:

result = "".join(re.findall(r'[^\W\d_]', text))

或者,删除与[\W\d_] 模式匹配的所有字符(与[^\W\d_] 相反):

result = re.sub(r'[\W\d_]+', '', text)

请参阅regex demo online但是,由于 Unicode 标准在不断发展,您可能会在不同的 Python 版本中得到不一致的结果,并且与 \w 匹配的字符集将取决于 Python 版本。强烈建议使用 PyPi regex 库以获得一致的结果。

【讨论】:

    【解决方案2】:

    试试:

    s = ''.join(filter(str.isalnum, s))
    

    这将从字符串中取出每个字符,只保留字母数字字符并从它们构建一个字符串。

    【讨论】:

    • 这很好,因为它可以处理像Å Å Ö这样的奇怪字符
    【解决方案3】:

    使用re.sub

    import re
    
    regex = re.compile('[^a-zA-Z]')
    #First parameter is the replacement, second parameter is your input string
    regex.sub('', 'ab3d*E')
    #Out: 'abdE'
    

    或者,如果您只想删除某组字符(因为在您的输入中可以使用撇号...)

    regex = re.compile('[,\.!?]') #etc.
    

    【讨论】:

    • 嗯,我可以很好地找到它,但是删除所有非字母数字(不包括空格)的模式呢?
    • 只需在您的收藏类中添加一个空格。即^a-zA-Z 而不仅仅是^a-zA-Z
    • 除非你也担心换行,在这种情况下a-zA-Z \n。我试图找到一个将两者合二为一的正则表达式,但使用 \w\W 并没有给我想要的行为。如果是这种情况,您可能只需要添加 \n
    • 啊,换行符。那就是我的问题所在,我正在将我的结果与给定的结果进行比较,但我仍然没有。我想这是我的问题!谢谢 // 嗯,我用换行符尝试了相同的结果,我想还有一个我错过了.. // Duhhh... 大写和小写... // 感谢所有的帮助,现在完美!
    【解决方案4】:

    最快的方法是正则表达式

    #Try with regex first
    t0 = timeit.timeit("""
    s = r2.sub('', st)
    
    """, setup = """
    import re
    r2 = re.compile(r'[^a-zA-Z0-9]', re.MULTILINE)
    st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
    """, number = 1000000)
    print(t0)
    
    #Try with join method on filter
    t0 = timeit.timeit("""
    s = ''.join(filter(str.isalnum, st))
    
    """, setup = """
    st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
    """,
    number = 1000000)
    print(t0)
    
    #Try with only join
    t0 = timeit.timeit("""
    s = ''.join(c for c in st if c.isalnum())
    
    """, setup = """
    st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
    """, number = 1000000)
    print(t0)
    
    
    2.6002226710006653 Method 1 Regex
    5.739747313000407 Method 2 Filter + Join
    6.540099570000166 Method 3 Join
    

    【讨论】:

      【解决方案5】:

      如果你不想使用正则表达式,你可以试试

      ''.join([i for i in s if i.isalpha()])
      

      【讨论】:

      • 如何加入?与 ''.join ?打印 s 只得到一个过滤器对象
      • 哇,这就是我想要的。这考虑了汉字、平假名、片假名等。荣誉
      【解决方案6】:

      您可以使用 re.sub() 函数删除这些字符:

      >>> import re
      >>> re.sub("[^a-zA-Z]+", "", "ABC12abc345def")
      'ABCabcdef'
      

      re.sub(匹配模式,替换字符串,要搜索的字符串)

      • "[^a-zA-Z]+" - 寻找任何不是的字符组 a-zA-z。
      • "" - 用“”替换匹配的字符

      【讨论】:

      • 请注意,这也会删除重音字母:ãâàéèçõ 等
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-30
      • 2015-02-26
      • 2022-01-09
      • 2018-12-02
      • 1970-01-01
      • 2013-01-19
      • 2021-09-02
      相关资源
      最近更新 更多