PHP:如何从文件的第n行替换第m行?

时间:2017-11-02 09:33:34

标签: php file fopen fwrite

我有一个像some.txt这样的文件,内容为:

#start-first
Line 1
Line 2
Line 3
#end-first

#start-second
Line 1
Line 2
Line 3
Line 4
#end-second

#start-n
Line 1
Line 2
Line 3
Line 4
...
...
#end-n

我想从#start-second#end-second或从#start-n#end-n删除文件中的内容,实际上#start-second启动标记 for 第二个文本块文件,#end-second结束标记 第二个文本块文件。

如何将特定起始块中的内容删除到同一个结束块?

2 个答案:

答案 0 :(得分:2)

如果这些文件非常大,那么有一个相当轻量级的解决方案:

$file = file_get_contents("example.txt");
// Find the start "#start-$block", "#end-$block" and the length between them:
$start = strpos($file, "#start-$block");
$end = strpos($file, "#end-$block");
$length = $end-$start+strlen("#end-$block");

$file = substr_replace($file, '', $start, length);
file_put_contents("example.txt", $file);

我的原始答案始于正则表达式:

$block = 4;

// Open the file
$file = openfile("example.txt");

// replace #start-$block, #end-$block, and everything inbetween with ''
$file = preg_replace("/#start\-".$block."(?:.*?)#end\-".$block."/s", '', $file);

// Save the changes
file_put_contents("example.txt", $file);

但是,正则表达式很昂贵,但有时更容易理解。

答案 1 :(得分:0)

这是我的解决方案:

逐行执行它有点困难,但它确实可以让您更好地管理大型文件的内存,因为您不能一次性打开整个文件。此外,您可以通过这种方式更轻松地替换多个块。

var obj = {
        aray1:[1,2],
        aray2:["a","b"],
        aray3:["ab","abab"]
};
var result = "";
for(key in obj){
	result += ","+obj[key].join(",")
}
console.log(result.substring(1));

输出

$file = 'test.txt';
//open file to read from
$f = fopen(__DIR__.DIRECTORY_SEPARATOR.$file,'r');
//open file to write to
$w = fopen(__DIR__.DIRECTORY_SEPARATOR.'out-'.$file,'w');

$state = 'start';  //start, middle, end

//start - write while looking for a start tag ( set to middle )
//middle - skip while looking for end tag  ( set to end )
//end - skip while empty ( set to start when not )

//Tags
$start = ['#start-second'];
$end = ['#end-second'];

 //read each line from the file
while( $line = fgets($f)){     
    if( $state == 'end' && !empty(trim($line))){
        //set to start on first non empty line after tag
        $state = 'start';
    }

    if( $state == 'start' ){
        if(in_array(trim($line),$start)){
            $state = 'middle';
        }else{
            fwrite($w, $line);
        }
    }else if( $state == 'middle' ){
        if(in_array(trim($line),$end)){
            $state = 'end';
        }
    }   
}
//close both files
fclose($f);
fclose($w);

//delete the input file
//unlink(__DIR__.DIRECTORY_SEPARATOR.$file);

//for debugging only
echo "<pre>";
echo file_get_contents(__DIR__.DIRECTORY_SEPARATOR.'out-'.$file)

这也会接受一系列标记,因此您可以逐个删除多个块。

出于安全原因,大多数PHP沙箱(或一般的代码沙箱)都会阻止您使用这些功能。也就是说,我们可以在某种程度上#start-first Line 1 Line 2 Line 3 #end-first #start-n Line 1 Line 2 Line 3 Line 4 ... ... #end-n 代码的主体,解析位。这就是我在这里所做的。

http://sandbox.onlinephpfunctions.com/code/0a746fb79041d30fcbddd5bcb00237fcdd8eea2f

这样你可以尝试一些不同的标签,看看它是如何工作的。为了获得额外的功劳,你可以将它变成一个接受文件路径和一系列open和start标签的函数。

emulate