2016-06-21 7 views
1

ハード・ラップを含むテキスト・ファイルがたくさんあります(改行は約80文字です)。私はそれを元に戻して、それらの文章をすべて一緒に結合したいが、新しい章や段落である新しい行を維持したい。新しい行がスペースで区切られていて、新しい改行がない場合(テキストの改行を元に戻す)

すなわちIdが\ n「の

「と次の文字が別でない場合だけ」次のPythonコードは、私が何をしたいんではなく、非常に効率的に、そしてI」と「N \」を置換したいですむしろ正規表現やsedでそれをやります。

s = open(filename, 'r').read() 
p = s.split('\n\n') # split into paragraphs 
p = [x.replace('\n', ' ') for x in p] # iterate all paragraphs, replace \n 
s2 = '\n\n'.join(p) # join paragraphs back together 

Lorem ipsum dolor sit amet, consectetur adipiscing 
elit. Vivamus porta dui quis aliquet interdum. Sed 
in pellentesque libero. Quisque tempus nisl nec 
nisl condimentum ullamcorper. 

Mauris vulputate nibh nec ipsum mattis rutrum. 
Nunc nec tristique magna, non sagittis lacus. 
Aliquam id urna lectus. 

Maecenas volutpat libero quis erat mollis, et 
aliquet purus dignissim. Sed faucibus, lectus in 
auctor ornare, dolor libero ultrices sem, vel 
iaculis ex nulla quis lacus. 

はなるはずです。

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus porta dui quis aliquet interdum. Sed in pellentesque libero. Quisque tempus nisl nec nisl condimentum ullamcorper. 

Mauris vulputate nibh nec ipsum mattis rutrum. Nunc nec tristique magna, non sagittis lacus. Aliquam id urna lectus. 

Maecenas volutpat libero quis erat mollis, et aliquet purus dignissim. Sed faucibus, lectus in auctor ornare, dolor libero ultrices sem, vel iaculis ex nulla quis lacus. 

更新

私が試したし、5メガバイトのテキストファイルに以下の5つのPythonのメソッドを時限ました。 3つの正規表現のすべてのメソッドが、Pythonの分割/置換/結合メソッドよりも1桁遅いことがわかりました。

def m1(s): 
    p = s.split('\n\n') # split into paragraphs 
    p = [x.replace('\n', ' ') for x in p] # iterate all paragraphs, replace \n 
    r = '\n\n'.join(p) # join paragraphs back together 
    return r 

def m2(s): 
    r = re.sub(r"(?<!\n)\n(?!\n)", " ", s) 
    return r 

def m3(s): 
    p = re.compile(ur'(?<!^)\n(?=\S)', re.MULTILINE) 
    r = re.sub(p, u" ", s) 
    return r 

def m4(s): 
    r = "".join(["".join(v) if k else " ".join(map(str.strip, v))+"\n" for k, v in groupby(s, str.isspace)]) 
    return r 


def repl(m): 
    return (' ' if len(m.group(1))==1 else m.group(1)) + m.group(2) 
def m5(s): 
    r = re.sub(r'(\n+)(.)', repl, s) 
    return r 

結果:

np.array(timeit.repeat('r=m1(s)', 'from __main__ import *', repeat=5, number=N))/N 
Out[4]: array([ 0.01343679, 0.0136183 , 0.0153013 , 0.0122381 , 0.01205051]) 

np.array(timeit.repeat('r=m2(s)', 'from __main__ import *', repeat=5, number=N))/N 
Out[5]: array([ 0.10881839, 0.108728 , 0.10904381, 0.10862441, 0.10867569]) 

np.array(timeit.repeat('r=m3(s)', 'from __main__ import *', repeat=5, number=N))/N 
Out[6]: array([ 0.1358021 , 0.1352592 , 0.13556101, 0.1357465 , 0.1354876 ]) 

np.array(timeit.repeat('r=m4(s)', 'from __main__ import *', repeat=5, number=N))/N 
Out[7]: array([ 2.51403842, 2.37821078, 2.4169096 , 2.56688828, 2.36240571]) 

np.array(timeit.repeat('r=m5(s)', 'from __main__ import *', repeat=5, number=N))/N 
Out[8]: array([ 0.16381941, 0.1616353 , 0.1620033 , 0.1617353 , 0.1615443 ]) 

答えて

0

使用re.sub()、その後、あなたは負 ルックの背後にあると先読みassertationsと周りにプレイしています。あなたの入力が大きい場合、これはあまり効率的ではありません。

ルックの背後にある:

(?<!...) 
    Matches if the current position in the string is not preceded by a match for .... This is called a negative lookbehind assertion. Similar to positive lookbehind assertions, the contained pattern must only match strings of some fixed length. Patterns which start with negative lookbehind assertions may match at the beginning of the string being searched. 

先読み:

(?!...) 
    Matches if ... doesn’t match next. This is a negative lookahead assertion. For example, Isaac (?!Asimov) will match 'Isaac ' only if 
it’s not followed by 'Asimov'. 

ここでは例です:

>>> text = """Lorem ipsum dolor sit amet, consectetur adipiscing 
elit. Vivamus porta dui quis aliquet interdum. Sed 
in pellentesque libero. Quisque tempus nisl nec 
nisl condimentum ullamcorper. 

Mauris vulputate nibh nec ipsum mattis rutrum. 
Nunc nec tristique magna, non sagittis lacus. 
Aliquam id urna lectus. 

Maecenas volutpat libero quis erat mollis, et 
aliquet purus dignissim. Sed faucibus, lectus in 
auctor ornare, dolor libero ultrices sem, vel 
iaculis ex nulla quis lacus.""" 

>>> re.sub(r"(?<!\n)\n(?!\n)", " ", text) 
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus porta dui quis aliquet interdum. Sed in pellentesque libero. Quisque tempus nisl nec nisl condimentum ullamcorper.\n\nMauris vulputate nibh nec ipsum mattis rutrum. Nunc nec tristique magna, non sagittis lacus. Aliquam id urna lectus.\n\nMaecenas volutpat libero quis erat mollis, et aliquet purus dignissim. Sed faucibus, lectus in auctor ornare, dolor libero ultrices sem, vel iaculis ex nulla quis lacus.' 

>>> print(_) 
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus porta dui quis aliquet interdum. Sed in pellentesque libero. Quisque tempus nisl nec nisl condimentum ullamcorper. 

Mauris vulputate nibh nec ipsum mattis rutrum. Nunc nec tristique magna, non sagittis lacus. Aliquam id urna lectus. 

Maecenas volutpat libero quis erat mollis, et aliquet purus dignissim. Sed faucibus, lectus in auctor ornare, dolor libero ultrices sem, vel iaculis ex nulla quis lacus. 
+0

ありがとうございました。なぜこれが投票権を得たのか分かりません。それは私のために働いた。 ( "\ n(?!\ n)"、 ""、text) – memo

+3

私は、このような場合には、これは段落を保存しません。 – hek2mgl

+0

実際に段落を保存しました。 – memo

0

あなたはこのように、そのためawkを使用することができます。

awk '{$1=$1}1' RS='' ORS='\n\n' OFS=' ' file 

説明:それは何も変わっていないだろうよう

  • {$1=$1}が見えます。それは本当だが、それでもawk

  • 1常に何のアクションが指定されていないため、awkは

  • RS=''は全体の現在のレコードが印刷されます、trueと評価(下記をご覧)新しいセパレータを使用してレコードを再構成します入力レコードセパレータ。空文字列は特別な値です。それは、空の行とフィールドを新しい行で分割記録することを意味します。

  • ORS='\n\n'セットの出力レコードセパレータも空白行にします。

  • OFS=' 'セットの出力フィールドセパレータをスペースに変換します。

出力:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus porta dui quis aliquet interdum. Sed in pellentesque libero. Quisque tempus nisl nec nisl condimentum ullamcorper. 

Mauris vulputate nibh nec ipsum mattis rutrum. Nunc nec tristique magna, non sagittis lacus. Aliquam id urna lectus. 

Maecenas volutpat libero quis erat mollis, et aliquet purus dignissim. Sed faucibus, lectus in auctor ornare, dolor libero ultrices sem, vel iaculis ex nulla quis lacus. 
+0

ありがとう、私はawkについて知りませんでした。それをチェックします。他のものにも非常に便利です。 – memo

+0

うん。プラスそれは正規表現の解決策に比べて速いです – hek2mgl

0

あなたは空白にグループ化、GROUPBYを使用することができます。

あなたを与えるだろう
from itertools import groupby 

with open("test.txt") as f: 
    print("".join(["".join(v) if k else " ".join(map(str.strip, v))+"\n" for k, v in groupby(f, str.isspace)])) 

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus porta dui quis aliquet interdum. Sed in pellentesque libero. Quisque tempus nisl nec nisl condimentum ullamcorper. 

Mauris vulputate nibh nec ipsum mattis rutrum. Nunc nec tristique magna, non sagittis lacus. Aliquam id urna lectus. 

Maecenas volutpat libero quis erat mollis, et aliquet purus dignissim. Sed faucibus, lectus in auctor ornare, dolor libero ultrices sem, vel iaculis ex nulla quis lacus. 
+0

おかげで、私はgroupbyについて知りませんでしたが、それは分割/置換/結合よりもかなり遅く実行されました。 – memo

+0

@memo、groupyはCレベルで起こるので、かなり効率的です。 –

0

私は、次の試してみましたPythonの正規表現:

text変数と仮定すると、あなたのサンプルテキスト

import re 
p = re.compile(ur'(?<!^)\n(?=\S)', re.MULTILINE) 

result = re.sub(p, u" ", text) 
print(result) 

それはスペースで改行を置き換える、次のテキストが出力されますが含まれています。 regex101

0

時には複雑な代替品で

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus porta dui quis aliquet interdum. Sed in pellentesque libero. Quisque tempus nisl nec nisl condimentum ullamcorper. 

Mauris vulputate nibh nec ipsum mattis rutrum. Nunc nec tristique magna, non sagittis lacus. Aliquam id urna lectus. 

Maecenas volutpat libero quis erat mollis, et aliquet purus dignissim. Sed faucibus, lectus in auctor ornare, dolor libero ultrices sem, vel iaculis ex nulla quis lacus. 

参照のデモはre.sub()に第二パラメータとしての関数を渡すことによって達成することができます。

import re 

ipsum = '''Lorem ipsum dolor sit amet, consectetur adipiscing 
elit. Vivamus porta dui quis aliquet interdum. Sed 
in pellentesque libero. Quisque tempus nisl nec 
nisl condimentum ullamcorper. 

Mauris vulputate nibh nec ipsum mattis rutrum. 
Nunc nec tristique magna, non sagittis lacus. 
Aliquam id urna lectus. 

Maecenas volutpat libero quis erat mollis, et 
aliquet purus dignissim. Sed faucibus, lectus in 
auctor ornare, dolor libero ultrices sem, vel 
iaculis ex nulla quis lacus. 
''' 

ipsum = re.sub(
    r'(\n+)(?=.)', 
    lambda m: ' ' if len(m.group(1))==1 else m.group(1), 
    ipsum) 

print ipsum 
関連する問題