Search in txt file, sum +1 and write the file - php

Good day guys,
I am really nowhere to the guy who do PHP coding, so I am asking you.
I have file in txt format and in that file somewhere I am having line with "count: (n)", where "(n)" can be any numeric value.
I need to search for count: (n), take the (n) value, sum it with +1 and save the file again.
So if I will have count: 10 it must be 10 + 1 = 11.
Thank you!

You'll probably want to use some regex to parse the 'count: n' string from the file. Although my regex is kind of rusty, this pattern might help:
$file = fopen('text.txt', 'r+'); // Open the file for reading and writing into the variable $file.
$fileContents = file_get_contents($file); // Load the contents of the file to variable $fileContents.
$countString = preg_match('/count: [0-9]+/', $fileContents); // Find instances of string 'count: n' where n is an integer, load the string into $countString.
$count = preg_match('/[0-9]+/', $countString); // Find the integer from $countString, load into $count.
$count++; // Iterate count up one.
$newCountString = 'count: '.$count; // The 'count: n+1' string where n is the original integer.
$newFileContents = preg_replace('/count: [0-9]+/', $newCountString, $fileContents); // Find the string 'count: n' and replace with 'count: n+1' where n is the original integer.
fwrite($file, $newFileContents); // Write the new contents into the file.
fclose($file);
Good luck!

Related

fgets() returning empty string

I am trying to read the first line in a text file, but the fgets() function does not seem to be doing the job. I have a hunch that it might be due to the way the new lines are done in the string, but I am not very experienced in the different ways that a new line can be denoted. I have an image from a website showing what the new lines are inputted as below as well as my code.
link(no rep for images): https://i.gyazo.com/373e217112edbfce272f82b2dae6b317.png
I have already tried changing the mode from w to w+ which I thought would fix the problem, but it did not. I also tried trimming the string using the trim() function in php but that also did not work. I have verified that I am actually writing into the file as well.
Here is the code,
<?php
$input = "def sum(numbers):
total = 0
for x in numbers:
total += x
return total
print(sum((8, 2, 3, 0, 7)))";
$answerFile = fopen("/afs/cad.njit.edu/u/a/j/ajr74/public_html/answer.txt", "w+") or die("Unable to open file.");
fwrite($answerFile, $input);
$line = fgets($answerFile);
print($line);
?>
I am expecting the output to be the first line of the file before the first CR LF tags, but I am getting an empty output instead.
I guess the file pointer is at the end. To bring it back you can use rewind in between writing to your file and reading from it.
So
fwrite($answerFile, $input);
$line = fgets($answerFile);
Becomes
fwrite($answerFile, $input);
rewind($answerFile);
$line = fgets($answerFile);
Note: that's aside from the fact that you already have the content. Normally you wouldn't really need to read form the file, you could just extract the first line from $input. But I guess that you're either just learning or planning to do this in two different points.
Interesting.
After performing a write, you would need to reset the pointer to read the contents back. Best way is to close it and open it for reading.
<?php
$input = "def sum(numbers):
total = 0
for x in numbers:
total += x
return total
print(sum((8, 2, 3, 0, 7)))";
//$file_name = "/afs/cad.njit.edu/u/a/j/ajr74/public_html/answer.txt";
$file_name = "./answer.txt";
echo "Write {$file_name} and Read back a line<br>";
$answerFileHandle = fopen($file_name, "w+") or die("Unable to open file.");
fwrite($answerFileHandle, $input);
// Required these two lines to close and re-open the file.
// Resets the pointer after the write operation above
fclose($answerFileHandle);
$answerFileHandle = fopen($file_name, "r") or die("Unable to open file.");
$line = fgets($answerFileHandle);
echo $line;
fclose($answerFileHandle);
Output is:
`Write ./answer.txt and Read back a line
def sum(numbers):`

PHP: Filtering and posting a text file

I have a text file that contains a persons surname, address, time of accident and reason of accident separated by a white space in a line. I need to filter this file by only the people that have called in at least two times for the same reason and echo it.
I'm fairly new to PHP so I would like a simple way. :)
Thank you.
EDIT:
I haven't tried anything since I have no clue how to even filter file contents.
$data = array($_POST['surname'], $_POST['address'], $_POST['time'], $_POST['reason']);
$info = implode(" ", $data)
$info .= "\r\n";
serialize($info);
file_put_contents("data.txt", $info, FILE_APPEND);
serialize($info);
This is how I wrote it into a file.
I imploded the file because I needed to make them separated by 3 white spaces, but it no longer matters so I can just keep the array.
The expected output should be something like this:
Surname Address Time Reason
Adams Railroad 5 13:20 Heart Attack
Adams Railroad 5 23:35 Heart Attack
It would only need to repeat the same people that have matching Surnames and Reasons.
Update
your text file contains string, entries seprated by line brakes and values by three spaces (actually html coded spaces).
Here we read whole txt file in,(some could do this line by line):
$whole_string = file_get_contents('data.txt');
So firstly we get each line:
$entries = explode('\n',$whole_string);
Then value arrays are pushed:
$whole_ar = array();
foreach($entries as $e){
$whole_ar[] = explode(' ',$e);
}//if 3 spaces in file are in html
We get:
array(
array(
'name','date','etc..'
),
array(
'name2','date','etc..'
),
array(
'name2','date','etc..'
)
)
You could store array in php file, for later to include('data.php'); like so:
$file = '<?php $whole_ar='.var_export($whole_ar, TRUE)."; ?>";
file_put_contents('data.php', $file);
Main answer on how to parse this array to target copies is iteritating or:
$answer = array_unique(array_diff_assoc($whole_ar, array_unique( $whole_ar)));
As I understand, you get information like this string when user calls in:
$newest = "Huchinson Estonia Tallin Geo street 13 2015.12.02 13:44 Gas leak"
You have this string in variable, like stated above.
Then you could explode string by space characters: $data = explode(" ",$newest); which gives you an array with number of values. First value will be a surname and last will be reason of accident.
Parse them out of array like this: echo $data[0];//this will be surname and echo end($data);//this will be accident type
Instead of echo you can assign these values to variables and look up if this surname AND accident is present in your database:
if($saved_before == $data[0].end($data)){
echo "we are working on ".end($data).", be patient, dear ".$data[0];
}
p.s. dot (.) is for concatenating strings
If i understand well the txt file is a csv file that uses a space as the delimenter of the columns. So use use fgetcsv function to load columns of each row. Specify the blank space as the delimiter.
That should get you started:
function parseIt($line) { return str_getcsv($line, " "); }
$all = array_map('parseIt', file('yourfile.txt'));
$names = array();
foreach ($all as $row) {
$uniqkey = $row[0].$row[3];
if (isset($names[$uniqkey])) {
echo implode(" ",$row);
$names[$uniqkey]++;
} else {
$names[$uniqkey] = 1;
}
}
I noticed in your file writing code you use a delimiter of 3 white spaces so I used it in the example - you can set it to whatever you want in the str_getcsv(line, delimiter)
Explanation:
Lines 1,2 - file() will read the file into an array that are passed through the function parseIt() this function will parse the line and return an array of the line value.
Line 3 - The array $names will act our memory, at the end it will hold all names + reason as keys and the value will be the counter of occurrences.
Line 4... - Loops through $all checks if the key exists in $names if it does it prints the row and moves the counter otherwise sets a new key in $names and set its value to 1 (counter).

Find all occurrences of a string in a file

Please keep in mind the file I am opening can be 10mb to 125mb. I have researched various ways to open a file and am still not sure as to the best approach if any one is best. Please advise!
I am opening a large file and trying to extract the text between two strings each time the first occurs. I can find the first string and extract the text to the second string, however, my loop gives me that result 12 times (number of times string occurs in this file. I can see what I am doing wrong in the loop, basically finding the first occurrence and repeating its output 12 times. How can I loop through the file and get the text between the 2-12th occurrences?
Also, any tips for proper opening of large files and handling memory limits would be great.
If this is put in an array, do I lose the whitespace? I am using PRE to display it correctly as it is. Ultimately, I want to parse each string found into smaller elements either in an array or a db. I don't want to get ahead of myself, so ignore the array comments if necessary.
<?php
ini_set('memory_limit', '-1');
/*
Functions
*/
function get_string_between($string, $start, $end){
$string = " ".$string;
$ini = strpos($string,$start);
if ($ini == 0) return "";
$ini += strlen($start);
$len = strpos($string,$end,$ini) - $ini;
return substr($string,$ini,$len);
}
/*
Pre Loop
*/
$string1 = "String 1";
$string2 = "String 2";
$report = file_get_contents('report.rpt','r');
$cbcount = substr_count($report,$string1);
echo $cbcount;
/*
Loop
*/
for ($i=0; $i<$cbcount; $i++){
$output = get_string_between($report, $string1, $string2);
echo "<pre>".$output."</pre>";
}
?>
You're never actually advancing any pointer of any kind, so it has no way of knowing that it already found the first match.
Now, depending on your input, you may be able to just use a regex:
preg_match_all("(".preg_quote($string1).".*?".preg_quote($string2).")s",$report,$matches);
(Replace the entire loop with this)
Then you can var_dump($matches[0]) to see your output.
$startfrom = 0;
while (($start = strpos($string1, $report, $startfrom)) !== false) {
$end = strpos($string2, $report, $start);
echo "<pre>".substr($report, $start, $end-$start)."</pre>";
$startfrom = $end + 1;
}
Regarding dealing with large files, instead of reading the entire thing into memory, you can use fopen() and fgets() to read it line by line. When you find a line containing the $string1 you start accumulating lines in in a variable, until you find the line containing $string2. This only works simply if the match strings cannot contain newlines.

php simplest case regex replacement, but backtraces not working

Hacking up what I thought was the second simplest type of regex (extract a matching string from some strings, and use it) in php, but regex grouping seems to be tripping me up.
Objective
take a ls of files, output the commands to format/copy the files to have the correct naming format.
Resize copies of the files to create thumbnails. (not even dealing with that step yet)
Failure
My code fails at the regex step, because although I just want to filter out everything except a single regex group, when I get the results, it's always returning the group that I want -and- the group before it, even though I in no way requested the first backtrace group.
Here is a fully functioning, runnable version of the code on the online ide:
http://ideone.com/2RiqN
And here is the code (with a cut down initial dataset, although I don't expect that to matter at all):
<?php
// Long list of image names.
$file_data = <<<HEREDOC
07184_A.jpg
Adrian-Chelsea-C08752_A.jpg
Air-Adams-Cap-Toe-Oxford-C09167_A.jpg
Air-Adams-Split-Toe-Oxford-C09161_A.jpg
Air-Adams-Venetian-C09165_A.jpg
Air-Aiden-Casual-Camp-Moc-C09347_A.jpg
C05820_A.jpg
C06588_A.jpg
Air-Aiden-Classic-Bit-C09007_A.jpg
Work-Moc-Toe-Boot-C09095_A.jpg
HEREDOC;
if($file_data){
$files = preg_split("/[\s,]+/", $file_data);
// Split up the files based on the newlines.
}
$rename_candidates = array();
$i = 0;
foreach($files as $file){
$string = $file;
$pattern = '#(\w)(\d+)_A\.jpg$#i';
// Use the second regex group for the results.
$replacement = '$2';
// This should return only group 2 (any number of digits), but instead group 1 is somehow always in there.
$new_file_part = preg_replace($pattern, $replacement, $string);
// Example good end result: <img src="images/ch/ch-07184fs.jpg" width="350" border="0">
// Save the rename results for further processing later.
$rename_candidates[$i]=array('file'=>$file, 'new_file'=>$new_file_part);
// Rename the images into a standard format.
echo "cp ".$file." ./ch/ch-".$new_file_part."fs.jpg;";
// Echo out some commands for later.
echo "<br>";
$i++;
if($i>10){break;} // Just deal with the first 10 for now.
}
?>
Intended result for the regex: 788750
Intended result for the code output (multiple lines of): cp air-something-something-C485850_A.jpg ./ch/ch-485850.jpg;
What's wrong with my regex? Suggestions for simpler matching code would be appreciated as well.
Just a guess:
$pattern = '#^.*?(\w)(\d+)_A\.jpg$#i';
This includes the whole filename in the match. Otherwise preg_replace() will really only substitute the end of each string - it only applies the $replacement expression on the part that was actually matched.
Scan Dir and Expode
You know what? A simpler way to do it in php is to use scandir and explode combo
$dir = scandir('/path/to/directory');
foreach($dir as $file)
{
$ext = pathinfo($file,PATHINFO_EXTENSION);
if($ext!='jpg') continue;
$a = explode('-',$file); //grab the end of the string after the -
$newfilename = end($a); //if there is no dash just take the whole string
$newlocation = './ch/ch-'.str_replace(array('C','_A'),'', basename($newfilename,'.jpg')).'fs.jpg';
echo "#copy($file, $newlocation)\n";
}
#and you are done :)
explode: basically a filename like blah-2.jpg is turned into a an array('blah','2.jpg); and then taking the end() of that gets the last element. It's the same almost as array_pop();
Working Example
Here's my ideaone code http://ideone.com/gLSxA

Manually move the fgetc file pointer to the next line

Question 1: How can I manually move the fgetc file pointer from its current location to the next line?
I'm reading in data character by character until a specified number of delimiters are counted. Once the delimiter count reaches a certain number, it needs to copy the remainder of the line until a new line (the record delimiter). Then I need to start copying character by character again starting at the next record.
Question 2: Is manually moving the file pointer to the next line the right idea? I would just explode(at "\n") but I have to count the pipe delimiters first because "\n" isn't always the record delimiter.
Here's my code (it puts all the data into the correct record until it reaches the last delimiter '|' in the record. It then puts the rest of the line into the next record because I haven't figured out how to make it correctly look for the '\n' after specified # of | are counted):
$file=fopen("source_data.txt","r") or exit ("File Open Error");
$record_incrementor = 0;
$pipe_counter = 0;
while (!feof($file))
{
$char_buffer = fgetc($file);
$str_buffer[] = $char_buffer;
if($char_buffer == '|')
{
$pipe_counter++;
}
if($pipe_counter == 46) //Maybe Change to 46
{
$database[$record_incrementor] = $str_buffer;
$record_incrementor++;
$str_buffer = NULL;
$pipe_counter = 0;
}
}
Sample Data:
1378|2009-12-13 11:51:45.783000000|"Pro" |"B13F28"||""|1||""|""|""|||False|||""|""|""|""||""||||||2010-12-15 11:51:51.330000000|108||||||""||||||False|""|""|False|""|||False
1379|2009-12-13 12:23:23.327000000|"TLUG"|"TUG"||""|1||""|""|""|||False|||""|""|""|""||""||||||1943-04-19 00:00:00|||||||""||||||False|""|""|False|""|||False
I'd say that doing this via file handling functions is a bit clumsy, when it could be done via regular expression quite easily. Just read the entire file into a string using file_get_contents() and doing a regular expression like /^(([^|]*\|){47}([^\r\n]*))/m with preg_match_all() could find you all the rows (which you can then explode() using | as the delimiter and setting 48 as the limit for number of fields.
Here is a working example function. The function takes the file name, field delimiter and the number of fields per row as the arguments. The function returns 2 dimensional array where first index is the data row number and the second is the field number.
function loadPipeData ($file, $delim = '|', $fieldCount = 48)
{
$contents = file_get_contents($file);
$d = preg_quote($delim, '/');
preg_match_all("/^(([^$d]*$d){" . ($fieldCount - 1) . '}([^\r\n]*))/m', $contents, $match);
$return = array();
foreach ($match[0] as $line)
{
$return[] = explode($delim, $line, $fieldCount);
}
return $return;
}
var_dump(loadPipeData('source_data.txt'));
(Note: this is a solution to the original problem)
You can read to the end of the line like this:
while (!feof($file) && fgetc($file) !== '\n');
As for whether or not fgetc is the right way to do this... your format makes it difficult to use anything else. You can't split on \n, because there may be newlines within a field, and you can't split on |, because the end of the record doesn't have a pipe.
The only other option I can think is to use preg_match_all:
$buffer = file_get_contents('test.txt');
preg_match_all('/((?:[^|]*\|){45}[^\n]*\n)/', $buffer, $matches);
foreach ($matches[0] as $row) {
$fields = explode('|', $row);
}
Answer to the modified question:
To read from the file pointer to the end of the line, you can simply use the file reading function fgets(). It returns everything from the current file pointer position until it reaches the end of the line (and also returns the end of the line character(s)). After the function call, the file reading pointer has been moved to the beginning of the next line.

Categories