2012-10-03 13 views
9

Czy istnieje sposób, bez podwójnej pętli do osiągnięcia tego, co wykonuje następujące polecenia sedpyton równoważne sed

Wejście:

Time 
Banana 
spinach 
turkey 

sed -i "/Banana/ s/$/Toothpaste/" file

wyjściowa:

Time 
BananaToothpaste 
spinach 
turkey 

Co mam do tej pory, to podwójna lista, która zajęłaby dużo czasu, aby przejść przez oba.

Lista a ma kilka numerów lista B ma taką samą masę numerów, ale w innej kolejności

Dla każdego wpisu w A chcę znaleźć linię B z tym samym numerem i wartość dodaną C do końca.

Mam nadzieję, że to ma sens, nawet jeśli mój przykład nie ma.

robiłem następujących w bash i to działa jednak to było bardzo powolne ...

for line in $(cat DATSRCLN.txt.utf8); do 
     srch=$(echo $line | awk -F'^' '{print $1}'); 
     rep=$(echo $line | awk -F'^' '{print $2}'); 
     sed -i "/$(echo $srch)/ s/$/^$(echo $rep)/" tmp.1; 
done 

Dzięki!

+3

Twój sed przykład nie jest równoznaczne z tym, czego rzeczywiście próbuje zrobić. –

+0

Tak więc w bash robiłem to i działało, ale super powolne ... – user1601716

+0

można faktycznie uruchomić sed w Pythonie za pomocą polecenia 'subprocess'. – karthikr

Odpowiedz

9

Stosując re.sub():

newstring = re.sub('(Banana)', r'\1Toothpaste', oldstring) 

ten chwyta jedną grupę (pomiędzy pierwszymi nawiasach) i zastępuje go przez sam (część \ ilość), a następnie pożądany sufiksu. Konieczne jest użycie r'' (nieprzetworzonego łańcucha), aby uciec został poprawnie zinterpretowany.

0

Jest to możliwe to zrobić przy użyciu pliku tmp z niskie wymagania systemowe i tylko jednej iteracji bez kopiowania całego pliku do pamięci:

#/usr/bin/python 
import tempfile 
import shutil 
import os 

newfile = tempfile.mkdtemp() 
oldfile = 'stack.txt' 

f = open(oldfile) 
n = open(newfile,'w') 

for i in f: 
     if i.find('Banana') == -1: 
       n.write(i) 
       continue 

     # Last row 
     if i.find('\n') == -1: 
       i += 'ToothPaste' 
     else: 
       i = i.rstrip('\n') 
       i += 'ToothPaste\n' 

     n.write(i) 

f.close() 
n.close() 

os.remove(oldfile) 
shutil.move(newfile,oldfile) 
2

Jeśli używasz Python3 następujący moduł pomoże Ci: https://github.com/mahmoudadel2/pysed

wget https://raw.githubusercontent.com/mahmoudadel2/pysed/master/pysed.py 

Umieść plik na swoim Python3 moduł moduły ścieżkę, a następnie:

import pysed 
pysed.replace(<Old string>, <Replacement String>, <Text File>) 
pysed.rmlinematch(<Unwanted string>, <Text File>) 
pysed.rmlinenumber(<Unwanted Line Number>, <Text File>) 
1

W rzeczywistości można wywołać sed z Pythona. Wiele sposobów na to, ale lubię używać modułu sh. (yum -y install python-sh)

Dane wyjściowe mojego przykładowego programu są następujące.

[[email protected] sh]$ cat input 
Time 
Banana 
spinich 
turkey 
[[email protected] sh]$ python test_sh.py 
[[email protected] sh]$ cat input 
Time 
Toothpaste 
spinich 
turkey 
[[email protected] sh]$ 

Oto test_sh.py

import sh 

sh.sed('-i', 's/Banana/Toothpaste/', 'input') 

to prawdopodobnie będzie działać tylko pod Linuksem.

3

Późno przybysz do wyścigu, tutaj jest moja implementacja w Pythonie dla sed:

import re 
import shutil 
from tempfile import mkstemp 


def sed(pattern, replace, source, dest=None, count=0): 
    """Reads a source file and writes the destination file. 

    In each line, replaces pattern with replace. 

    Args: 
     pattern (str): pattern to match (can be re.pattern) 
     replace (str): replacement str 
     source (str): input filename 
     count (int): number of occurrences to replace 
     dest (str): destination filename, if not given, source will be over written.   
    """ 

    fin = open(source, 'r') 
    num_replaced = count 

    if dest: 
     fout = open(dest, 'w') 
    else: 
     fd, name = mkstemp() 
     fout = open(name, 'w') 

    for line in fin: 
     out = re.sub(pattern, replace, line) 
     fout.write(out) 

     if out != line: 
      num_replaced += 1 
     if count and num_replaced > count: 
      break 
    try: 
     fout.writelines(fin.readlines()) 
    except Exception as E: 
     raise E 

    fin.close() 
    fout.close() 

    if not dest: 
     shutil.move(name, source) 

przykłady:

sed('foo', 'bar', "foo.txt") 

zastąpi wszystkie 'foo' z 'bar' w foo.txt

sed('foo', 'bar', "foo.txt", "foo.updated.txt") 

zastąpi wszystkie 'foo' z 'bar' w 'foo.txt' i zapisz wynik w "foo.updated.txt".

sed('foo', 'bar', "foo.txt", count=1) 

zastąpi tylko pierwsze wystąpienie „foo” z „bar” i zapisać wynik w oryginalnym pliku „foo.txt”