Python正则表达式删除空格并大写空格所在的字母?

时间:2012-08-22 21:31:04

标签: python regex tags python-2.7

我想从用户提供的单个输入框创建一个标记列表,用逗号分隔,我正在寻找一些可以帮助自动化的表达式。

我想要的是提供输入字段和:

  • 删除所有双+空格,制表符,新行(只留下单个空格)
  • 删除所有(单引号和双引号)引号,逗号除外,其中只有一个
  • 在每个逗号之间,我想要标题案例,但是排除第一个单词而不是单个单词,这样当删除最后一个空格时,标签会出现'somethingLikeTitleCase'或只是'某事'或'twoWords'
  • 最后,删除所有剩余空格

到目前为止,这是我收集的内容:

def no_whitespace(s):
"""Remove all whitespace & newlines. """
    return re.sub(r"(?m)\s+", "", s)


# remove spaces, newlines, all whitespace
# http://stackoverflow.com/a/42597/523051

  tag_list = ''.join(no_whitespace(tags_input))

# split into a list at comma's

  tag_list = tag_list.split(',')

# remove any empty strings (since I currently don't know how to remove double comma's)
# http://stackoverflow.com/questions/3845423/remove-empty-strings-from-a-list-of-strings

  tag_list = filter(None, tag_list)

虽然在修改正则表达式以删除除逗号之外的所有标点符号时我都迷失了,我甚至不知道从哪里开始大写。

有什么想法让我朝着正确的方向前进?


根据建议,这里有一些示例输入= desired_outputs

形式:'tHiS是一个'空白'!&#^,secondcomment,no!punc $$,ifNOSPACESthenPRESERVEcaps'应该出来     ['thisIsATag','secondcomment','noPunc','ifNOSPACESthenPRESERVEcaps']

3 个答案:

答案 0 :(得分:2)

这是问题的解决方法(不使用任何正则表达式,尽管有一个地方可以)。我们将问题分成两个函数:一个函数将字符串拆分为逗号分隔的部分并处理每个部分(parseTags),另一个函数接受字符串并将其处理为有效的标记({{1 }})。带注释的代码如下:

sanitizeTag

事实上,如果我们运行此代码,我们会得到:

# This function takes a string with commas separating raw user input, and
# returns a list of valid tags made by sanitizing the strings between the
# commas.
def parseTags(str):
    # First, we split the string on commas.
    rawTags = str.split(',')

    # Then, we sanitize each of the tags.  If sanitizing gives us back None,
    # then the tag was invalid, so we leave those cases out of our final
    # list of tags.  We can use None as the predicate because sanitizeTag
    # will never return '', which is the only falsy string.
    return filter(None, map(sanitizeTag, rawTags))

# This function takes a single proto-tag---the string in between the commas
# that will be turned into a valid tag---and sanitizes it.  It either
# returns an alphanumeric string (if the argument can be made into a valid
# tag) or None (if the argument cannot be made into a valid tag; i.e., if
# the argument contains only whitespace and/or punctuation).
def sanitizeTag(str):
    # First, we turn non-alphanumeric characters into whitespace.  You could
    # also use a regular expression here; see below.
    str = ''.join(c if c.isalnum() else ' ' for c in str)

    # Next, we split the string on spaces, ignoring leading and trailing
    # whitespace.
    words = str.split()

    # There are now three possibilities: there are no words, there was one
    # word, or there were multiple words.
    numWords = len(words)
    if numWords == 0:
        # If there were no words, the string contained only spaces (and/or
        # punctuation).  This can't be made into a valid tag, so we return
        # None.
        return None
    elif numWords == 1:
        # If there was only one word, that word is the tag, no
        # post-processing required.
        return words[0]
    else:
        # Finally, if there were multiple words, we camel-case the string:
        # we lowercase the first word, capitalize the first letter of all
        # the other words and lowercase the rest, and finally stick all
        # these words together without spaces.
        return words[0].lower() + ''.join(w.capitalize() for w in words[1:])

此代码中有两点值得澄清。首先是在>>> parseTags("tHiS iS a tAg, \t\n!&#^ , secondcomment , no!punc$$, ifNOSPACESthenPRESERVEcaps") ['thisIsATag', 'secondcomment', 'noPunc', 'ifNOSPACESthenPRESERVEcaps'] 中使用str.split()。这会将sanitizeTags变为a b c,而['a','b','c']会产生str.split(' ')。这几乎肯定是你想要的行为,但有一个角落的情况。考虑字符串['','a','b','c','']tAG$变成了一个空间,被分裂剥离了;因此,这会变成$而不是tAG。这可能是你想要的,但如果不是,你必须要小心。我要做的是将该行更改为tag,这将在空格上拆分字符串,但留在前导和尾随空字符串中;但是,我也会将words = re.split(r'\s+', str)更改为使用parseTags。你必须做出这两个改变; rawTags = re.split(r'\s*,\s*', str)您想要的行为,而'a , b , c'.split(',') becomes ['a ', ' b ', ' c']也会删除逗号周围的空格。如果忽略前导和尾随空格,则差异无关紧要;但如果你不这样做,那么你需要小心。

最后,不使用正则表达式,而是使用r'\s*,\s*'。如果需要,您可以使用正则表达式替换它。 (编辑:我在此处删除了有关Unicode和正则表达式的一些不准确之处。)忽略Unicode,您可以用

替换此行
str = ''.join(c if c.isalnum() else ' ' for c in str)

这使用str = re.sub(r'[^A-Za-z0-9]', ' ', str) 匹配所有列出的字符:ASCII字母和数字。但是,最好支持Unicode,而且也很简单。最简单的方法是

[^...]

此处,str = re.sub(r'\W', ' ', str, flags=re.UNICODE) 匹配非单词字符;单词字符是字母,数字或下划线。指定\W(在Python 2.7之前不可用;您可以使用flags=re.UNICODE用于早期版本 2.7),字母和数字都是任何适当的Unicode字符;没有它,它们只是ASCII。如果您不想使用下划线,可以将r'(?u)\W'添加到正则表达式以匹配下划线,也可以用空格替换它们:

|_

我认为,最后一个完全符合我的非正则表达式代码的行为。


此外,这是我如何在没有这些评论的情况下编写相同的代码;这也允许我消除一些临时变量。您可能更喜欢存在变量的代码;这只是一个品味问题。

str = re.sub(r'\W|_', ' ', str, flags=re.UNICODE)

要处理新期望的行为,我们必须做两件事。首先,我们需要一种方法来修复第一个单词的大写:如果第一个字母的小写,则小写整个小写,如果第一个字母的大写,则小写所有第一个字母。这很简单:我们可以直接检查。其次,我们希望将标点符号视为完全不可见:它不应该大写下面的单词。再说一次,这很容易 - 我甚至讨论如何处理上面类似的事情。我们只过滤掉所有非字母数字,非空白字符,而不是将它们转换为空格。纳入这些变化给了我们

def parseTags(str):
    return filter(None, map(sanitizeTag, str.split(',')))

def sanitizeTag(str):
    words    = ''.join(c if c.isalnum() else ' ' for c in str).split()
    numWords = len(words)
    if numWords == 0:
        return None
    elif numWords == 1:
        return words[0]
    else:
        return words[0].lower() + ''.join(w.capitalize() for w in words[1:])

运行此代码会为我们提供以下输出

def parseTags(str):
    return filter(None, map(sanitizeTag, str.split(',')))

def sanitizeTag(str):
    words    = filter(lambda c: c.isalnum() or c.isspace(), str).split()
    numWords = len(words)
    if numWords == 0:
        return None
    elif numWords == 1:
        return words[0]
    else:
        words0 = words[0].lower() if words[0][0].islower() else words[0].capitalize()
        return words0 + ''.join(w.capitalize() for w in words[1:])

答案 1 :(得分:0)

我认为这应该有用

def toCamelCase(s):
  # remove all punctuation
  # modify to include other characters you may want to keep
  s = re.sub("[^a-zA-Z0-9\s]","",s)

  # remove leading spaces
  s = re.sub("^\s+","",s)

  # camel case
  s = re.sub("\s[a-z]", lambda m : m.group(0)[1].upper(), s)

  # remove all punctuation and spaces
  s = re.sub("[^a-zA-Z0-9]", "", s)
  return s

tag_list = [s for s in (toCamelCase(s.lower()) for s in tag_list.split(',')) if s]

这里的关键是利用re.sub来进行你想要的替换。

编辑:不保留大写字母,但会处理带空格的大写字符串

编辑:在toCamelCase调用之后移动“if s”

答案 2 :(得分:0)

你可以使用允许在一个单词中的白色字符列表,其他一切都被忽略:

import re

def camelCase(tag_str):
    words = re.findall(r'\w+', tag_str)
    nwords = len(words)
    if nwords == 1:
        return words[0] # leave unchanged
    elif nwords > 1: # make it camelCaseTag
        return words[0].lower() + ''.join(map(str.title, words[1:]))
    return '' # no word characters

此示例使用\w个字符。

Example

tags_str = """ 'tHiS iS a tAg, 'whitespace' !&#^ , secondcomment , no!punc$$, 
ifNOSPACESthenPRESERVEcaps' """
print("\n".join(filter(None, map(camelCase, tags_str.split(',')))))

输出

thisIsATag
whitespace
secondcomment
noPunc
ifNOSPACESthenPRESERVEcaps