2009-10-27 15 views
8

私は切り詰める必要がある文字列のバッチを持っています。基本的には記述子の後にコードが続きます。私は記述子を保持したいだけです。特定のフレーズの後に文字列をスライスしますか?

'a descriptor dps 23 fd' 
'another 23 fd' 
'and another fd' 
'and one without a code' 

コードが上記dps23fdあります。それらは任意の順序で来ることができ、互いに無関係であり、全く存在しない可能性がある(最後の場合のように)。

コードのリストは固定です(または少なくとも予測できます)。したがって、コードが正当な記述子で使用されることがないと仮定すると、コードの最初のインスタンスの後にすべてを削除できます。

私はPythonを使用しています。 THC4Kはコメントで指摘@として

+4

、コードは何であり、どのような出力は次のようになります。私はあなたが例外を期待して好きではない場合は、トライキャッチを削除することができ、迅速に実現? –

答えて

21

短い答え、:、

stringがあなたの元の文字列である
string.split(pattern, 1)[0] 

patternはあなたの「休憩」のパターンである、1は1時間以下で分割しないように示し、 [0]はsplitによって返された最初の要素を取ります。アクションで

>>> s = "a descriptor 23 fd" 
>>> s.split("23", 1)[0] 
'a descriptor ' 
>>> s.split("fdasfdsafdsa", 1)[0] 
'a descriptor 23 fd' 

これは私が以前、私はとにかくここに保つであろう書かれていたものを表現するのはるかに短い方法です。

そして、あなたは複数のパターンを削除する必要がある場合、これはreduce組み込みのための偉大な候補である:

>>> string = "a descriptor dps foo 23 bar fd quux" 
>>> patterns = ["dps", "23", "fd"] 
>>> reduce(lambda s, pat: s.split(pat, 1)[0], patterns, string) 
'a descriptor ' 
>>> reduce(lambda s, pat: s.split(pat, 1)[0], patterns, "uiopuiopuiopuipouiop") 
'uiopuiopuiopuipouiop' 

これは基本的に言う:patternsの各patのために:上記の説明のように(stringを取り、繰り返しstring.split(pat, 1)[0]を適用)、毎回以前に返された値の結果を操作します。ご覧のように、文字列内にパターンがない場合、元の文字列が返されます。


最も簡単な答えはstring.findと組み合わせリスト/文字列のスライスです:

>>> s = "a descriptor 23 fd" 
>>> s[:s.find("fd")] 
'a descriptor 23 ' 
>>> s[:s.find("23")] 
'a descriptor ' 
>>> s[:s.find("gggfdf")] # <-- look out! last character got cut off 
'a descriptor 23 f' 

より良いアプローチ(欠落しているパターンときs.findリターン-1の最後の文字を遮断回避するため)可能性があります単純な関数でラップすること:

>>> def cutoff(string, pattern): 
...  idx = string.find(pattern) 
...  return string[:idx if idx != -1 else len(string)] 
... 
>>> cutoff(s, "23") 
'a descriptor ' 
>>> cutoff(s, "asdfdsafdsa") 
'a descriptor 23 fd' 

[:s.find(x)]構文は右Hまでのインデックス0から文字列の一部を取ることを意味結腸の側方および側部。この場合、RHSはs.findの結果となり、渡された文字列のインデックスが返されます。例えば

def get_descriptor(text): 
    codes = ('12', 'dps', '23') 
    for c in codes: 
     try: 
      return text[:text.index(c)].rstrip() 
     except ValueError: 
      continue 

    raise ValueError("No descriptor found in `%s'" % (text)) 

:あなたはこのような何かを説明しているように見える

+0

'the_string.split(pattern、1)[0]'は私の考えと同じです。 –

+0

良い目、@ THC4k。 –

+0

分割してマークすると、文字列にコードがない場合はどうなりますか?そして、両方で、一度に複数のコードをチェックする良い方法はありません。どちらの例も、一度に1つしか扱わないようです。 – Oli

2

>>> get_descriptor('a descriptor dps 23 fd') 
'a descriptor' 
1
codes = ('12', 'dps', '23') 

def get_descriptor(text): 
    words = text.split() 
    for c in codes: 
     if c in words: 
      i = words.index(c) 
      return " ".join(words[:i]) 
    raise ValueError("No code found in `%s'" % (text)) 
1

私はおそらくこれを行うには、正規表現を使用したい:

>>> import re 
>>> descriptors = ('foo x', 'foo y', 'bar $', 'baz', 'bat') 
>>> data = ['foo x 123', 'foo y 123', 'bar $123', 'baz 123', 'bat 123', 'nothing'] 
>>> p = re.compile("(" + "|".join(map(re.escape, descriptors)) + ")") 
>>> for s in data: 
     m = re.match(p, s) 
     if m: print m.groups()[0] 
foo x 
foo y 
bar $ 
baz 
bat 

あなたがそのテキストが含まれるように抽出しているものかどうか私には全く明確ではありませんでした記述子に先行するか、またはテキストの各行が記述子で始まることを期待する場合、上記は後者を扱う。かつてのために、ちょうどそれが記述子の最初の発生前のすべての文字をキャプチャするために、わずかにパターンを変更します。

>>> p = re.compile("(.*(" + "|".join(map(re.escape, descriptors)) + "))") 
0

ここでは、すべてのコードのためではなく、各コードのための関数を呼び出すためにあなたを強制的に働くの答えです、上記の答えのいくつかより少し単純です。それはあなたのすべての例にも当てはまります。

strings = ('a descriptor dps 23 fd', 'another 23 fd', 'and another fd', 
        'and one without a code') 
codes = ('dps', '23', 'fd') 

def strip(s): 
    try: 
     return s[:min(s.find(c) for c in codes if c in s)] 
    except ValueError: 
     return s 

print map(strip, strings) 

出力:

​​3210

私はこれがあなたの基準のすべてを満たすと考えています。

編集:あなたの例では

def strip(s): 
    if not any(c in s for c in codes): 
     return s 
    return s[:min(s.find(c) for c in codes if c in s)] 
関連する問題