3

Needed solution:

I am working with a simple PHP script that should:

  1. Add "value4:::" at the end of the first line in a file
  2. Add ":::" at the end of all the next lines

I am novise in programming, and have sit here for two days trying to figure this out. Might be a little detail, or it might be totally wrong way of doing this task.

It might be wrong way to do this, or may be a regex problem? I really don't know.

I kindly ask you to help me with the solution.


Information:

The file newstest.db looks like this:

ID:::value1:::value2:::value3:::
1:::My:::first:::line:::
2:::My:::second:::line:::
3:::Your:::third:::line:::

And using this php script I'd like to make it look like this:

ID:::value1:::value2:::value3:::value4:::
1:::My:::first:::line::::::
2:::My:::second:::line::::::
3:::Your:::third:::line::::::

Problem:

So far I have almost got it, but I am confused to why it adds the "value4:::" to the beginning of the second line, and then add ":::" at the beginning (not end) of all of the rest of the lines.

So I get a file that looks like this:

ID:::value1:::value2:::value3:::
value4:::1:::My:::first:::line:::
:::2:::My:::second:::line:::
:::3:::Your:::third:::line:::

I thought that:

$lineshere = 'Some text here:::';    
$lines1 = $linehere.'value4:::';

would output "Some text here:::value4:::"

May be the problem is due to this way of adding line after line?

$lines = '';
$lines.= 'My test';
$lines.= ' is here';
echo $lines;

I am a novise in programming, so I might have used totally wrong functions tec to make this work.

But in this case it seams to add a space or line break/ line end in the wrong place.


My try on this solution:

<?php
// specify the file
$file_source="newstest.db";

// get the content of the file
$newscontent = file($file_source, true);

//set a start value (clear memory)
$lines ='';

// get each line and treat it line by line. 

foreach ($newscontent as $line_num => $linehere) {  

    // add "value4:::" at the end of FIRST line only, and put it in memory $lines 
    if($line_num==0) {
        $lines.= $linehere.'value4:::';

        // Just to see what the line looks like
        //echo 'First line: '.$lines.'<br /><br />';
    }

    // then add ":::" to the other lines and add them to memory $lines
    if($line_num>0) {
        $lines1 = $linehere.':::';
        $lines.= $lines1;

        //just look at the line
        //echo 'Line #'.$line_num.': '.$lines1.'<br /><br />';
    }
}

//Write new content to $file_source
$f = fopen($file_source, 'w');
fwrite($f,$lines);
fclose($f);

echo "// to show the results ar array<br /><br />";

$newscontentlook = file($file_source, true);
print_r(array_values($newscontentlook));
?>
Preben
  • 1,277
  • 2
  • 11
  • 20
  • 1
    Just as a side note: you may want to look at your files using a hex editor to see the newline/ carriage return characters as well. – Matthias W. Apr 28 '16 at 09:53
  • I believe, this is due to the fact that $linehere ends with a linebreak. – Emanuel Oster Apr 28 '16 at 09:57
  • What is the purpose of `true` in the line `$newscontent = file($file_source, true);`? Change it to `FILE_IGNORE_NEW_LINES` and it should work. – SamWhan Apr 28 '16 at 10:05
  • this is very easy to achieve with `file_get_contents` and `preg_replace`, I've posted an answer below – Pedro Lobito Apr 28 '16 at 10:22
  • Thank you all so much. I am looking through all solutions suggested now :-) – Preben Apr 28 '16 at 10:54
  • @ClasG : When using `FILE_IGNORE_NEW_LINES` the flat file is saved with everything one one line. I need one line per ID. Please correct me if I added it wrong. I wrote `$newscontent = file($file_source, FILE_IGNORE_NEW_LINES);` – Preben Apr 28 '16 at 10:58
  • I'm (very) far from a php-expert, but reading the documentation it states `FILE_IGNORE_NEW_LINES - Do not add newline at the end of each array element`. [Check it here](http://php.net/manual/en/function.file.php) – SamWhan Apr 28 '16 at 11:01

3 Answers3

2

the function file() gives you the file in an array with each line being an element of the array. Each ending of the line (EOL) is included in the elements. So appending text to that line will be after the EOL, and thus effectively on the beginning of the next line.

You can either choose to not use file() and explode the text yourself on the EOL, so the EOL is no longer part of the array element. Then edit the elements, and implode the array again.

Or fopen() the file, and fread() through it yourself. The latter option is preferred, as it won't load the entire file into memory at once.

nl-x
  • 11,762
  • 7
  • 33
  • 61
  • Good explanation. Could be solved with the current approach though, by adding the flag `FILE_IGNORE_NEW_LINES` (if I'm not totally wrong). – SamWhan Apr 28 '16 at 10:03
2

This is actually very easy to achieve with file_get_contents and preg_replace, i.e:

$content = file_get_contents("newstest.db");
$content = preg_replace('/(^ID:.*\S)/im', '$1value4:::', $content);
$content = preg_replace('/(^\d+.*\S)/im', '$1:::', $content);
file_put_contents("newstest.db", $content);

Output:

ID:::value1:::value2:::value3:::value4:::
1:::My:::first:::line::::::
2:::My:::second:::line::::::
3:::Your:::third:::line::::::

Ideone Demo

Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
  • This was a clever approach. I have one problem though. It now adds "value4:::" as a new line below the first line etc. The same for each new ":::". Any idea why? Is it related to the way I get the contents of the file? – Preben Apr 28 '16 at 11:32
  • 1
    try adding `\S` at the end of both regexes, I've updated answer. `\S` Match a single character that is NOT a “whitespace character” (any Unicode separator, tab, line feed, carriage return, vertical tab, form feed, next line) «\S» – Pedro Lobito Apr 28 '16 at 11:35
  • I'm sorry. I am really noob when it comes to regex. I didn't understand where to put `\S` . I tried after the `im` but that didn't work. How should it look? – Preben Apr 28 '16 at 11:54
  • Just see me answer, it's there – Pedro Lobito Apr 28 '16 at 11:54
  • Oh. I looked in the answer above. I now see it in the link to deone.com – Preben Apr 28 '16 at 11:56
  • Thank you, that worked. Am now just testing with different values to see that it always works :-) – Preben Apr 28 '16 at 12:00
1

I think the problem is in your loop through the lines read by file() function:

foreach ($newscontent as $line_num => $linehere) {
  ...

$linehere contains a newline at the end, so you should simply chop it before using it:

foreach ($newscontent as $line_num => $linehere) {
  $linehere = chop($linehere);
  ...

If you don't chop the line contents, when you concatenate a string to it, you'll get:

LINE_CONTENTS\nSTRING_ADDED

which, when printed, will be:

LINE_CONTENTS
STRING_ADDED

Hope this helps...

MarcoS
  • 17,323
  • 24
  • 96
  • 174
  • This solved the space problem :-) However now everything is saved in ONE line when wrote back to the file. So I probably need to add a code that tells it to save each line with a "end of line"? Do you know how? – Preben Apr 28 '16 at 11:40
  • 1
    Yes: you can use `fputs()` instead of `fwrite()` when writing each line, or add a `\n` character at the end of each line before `fwrite()`... – MarcoS Apr 28 '16 at 12:15