1

ユーザーが指定した単一の入力ボックスからタグのリストをコンマで区切って作成したいのですが、これを自動化するのに役立つ式を探しています。

私が欲しいのは、入力フィールドを提供することです。

  • すべてのdouble+空白、タブ、新しい行を削除します(単一のスペースのみを残します)
  • すべての(シングルおよびダブル+)引用符を削除します。ただし、コンマは1つしか存在できません。
  • 各カンマの間に、タイトルケースのようなものが必要ですが、最初の単語を除外し、単一の単語にはまったく使用しないため、最後のスペースを削除すると、タグは「somethingLikeTitleCase」または「something」または「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 iS a tAg、' whitespace'!&#^、secondcomment、no!punc $$、ifNOSPACESthenPRESERVEcaps'は['thisIsATag'、'secondcomment'、'noPunc'、'ifNOSPACESthenPRESERVEcaps']として出力されます。

4

3 に答える 3

3

問題へのアプローチを次に示します (正規表現を使用していませんが、正規表現を使用できる場所が 1 つあります)。問題を 2 つの関数に分割します。1 つは文字列をカンマ区切りの断片に分割し、各断片を処理する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']

このコードには、明確にする価値のあるポイントが 2 つあります。まず in の使い方str.split()ですsanitizeTags。これは に変わりますa b c['a','b','c']str.split(' ')生成されるのは['','a','b','c','']です。これはほぼ間違いなくあなたが望む動作ですが、1 つのコーナー ケースがあります。文字列を考えてみましょう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*'、コンマの周りのスペースも削除します。先頭と末尾の空白を無視しても、違いは重要ではありません。そうでない場合は、注意が必要です。

最後に、正規表現を使用せず、代わりにstr = ''.join(c if c.isalnum() else ' ' for c in str). 必要に応じて、これを正規表現に置き換えることができます。(編集: Unicode と正規表現に関する不正確な部分をここで削除しました。) Unicode を無視すると、この行を次のように置き換えることができます。

str = re.sub(r'[^A-Za-z0-9]', ' ', str)

これは、リストされた文字 (ASCII 文字と数字)以外[^...]のすべてに一致するために使用されます。ただし、Unicode をサポートする方が優れており、それも簡単です。そのような最も単純なアプローチは、

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

ここでは、\W単語以外の文字に一致します。単語の文字は、文字、数字、またはアンダースコアです。指定するとflags=re.UNICODE(Python 2.7 より前では使用できません。代わりr'(?u)\W'に以前のバージョン2.7 で使用できます)、文字と数字はどちらも適切な Unicode 文字です。それがなければ、それらは単なる ASCII です。アンダースコアが必要ない場合は|_、正規表現に追加してアンダースコアも一致させ、それらもスペースに置き換えることができます。

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:])

新たに望ましい動作を処理するには、2 つのことを行う必要があります。まず、最初の単語の大文字化を修正する方法が必要です。最初の文字が小文字の場合は全体を小文字にし、最初の文字が大文字の場合は最初の文字以外をすべて小文字にします。それは簡単です。直接確認するだけです。第二に、句読点を完全に見えないように扱いたい: 後続の単語を大文字にすべきではありません。繰り返しますが、これは簡単です。上記と同様のものを処理する方法についても説明します。非英数字、非空白文字をスペースに変換するのではなく、すべて除外します。これらの変更を組み込むことで、

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:])

このコードを実行すると、次の出力が得られます

>>> parseTags("tHiS iS a tAg, AnD tHIs, \t\n!&#^ , se@%condcomment$ , No!pUnc$$, ifNOSPACESthenPRESERVEcaps")
['thisIsATag', 'AndThis', 'secondcomment', 'NopUnc', 'ifNOSPACESthenPRESERVEcaps']
于 2012-08-22T23:46:22.017 に答える
1

単語に使用できる文字のホワイト リストを使用できます。それ以外はすべて無視されます。

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単語の文字を使用しています。

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
于 2012-08-22T22:44:09.983 に答える
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 を使用して必要な置換を作成することです。

EDIT : 大文字は保持されませんが、スペースを含む大文字の文字列は処理されます

編集: toCamelCase 呼び出しの後に「if s」を移動しました

于 2012-08-22T22:03:12.193 に答える