How to count specific lines in a text file depending on a particular variable in that line.
For example i need to count the lines of a text file only containing for instance $item1 or $item2 etc.
Sounds like you need something like what grep -c do in the shell, try something like this:
$item1 = 'match me';
$item2 = 'match me too';
// Thanks to #Baba for the suggestion:
$match_count = count(
preg_grep(
'/'.preg_quote($item1).'|'.preg_quote($item2).'/i',
file('somefile_input.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
)
);
// does the same without creating a second array with the matches
$match_count = array_reduce(
file('somefile_input.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES),
function($match_count, $line) use ($item1, $item2) {
return
preg_match('/'.preg_quote($item1).'|'.preg_quote($item2).'/i', $line) ?
$match_count + 1 : $match_count;
}
);
The above code sample uses the file() function to read the file into an array (splitted by lines), array_reduce() to iterate that array and preg_match() inside the iteration to see if a line matched (the /i at the end makes it case-insensitive).
You could use a foreach as well too.
This code reads file.php and counts only lines containing '$item1' or '$item2'. The check itself could be finetuned, since you have to add a new stristr() for every word you want to check.
<?php
$file = 'file.php';
$fp = fopen($file, 'r');
$size = filesize($file);
$content = fread($fp, $size);
$lines = preg_split('/\n/', $content);
$count = 0;
foreach($lines as $line) {
if(stristr($line, '$item1') || stristr($line, '$item2')) {
$count++;
}
}
echo $count;
Read your file line by line and use strpos to determine if a line contains a specific string/item.
$handle = fopen ("filename", "r");
$counter = 0;
while (!feof($handle))
{
$line = fgets($handle);
// or $item2, $item3, etc.
$pos = strpos($line, $item);
if ($pos !== false)
{
$counter++
}
}
fclose ($handle);
Related
This question already has answers here:
Replace substrings with an incremented counter value
(5 answers)
Closed 2 years ago.
I have a text file (data.txt) with the following lines
# one
# two
a-two
b-two
c-two
# three
a-three
b-three
# four
I would like to replace # with incremental number per line so to be like this
1 one
2 two
a-two
b-two
c-two
3 three
a-three
b-three
4 four
I have try to do this
<?php
$path_to_file = 'data.txt';
$what_to_replace = '#';
$i = 0; // initial count
$file_contents = file_get_contents($path_to_file);
$file_contents = str_replace($what_to_replace, $i++,$file_contents);
file_put_contents($path_to_file,$file_contents);
?>
it did changed in all lines with # but not incrementally
Here's a simple way via preg_replace_callback():
$i = 1;
$file_contents = preg_replace_callback('/^#/m', function($match) use (&$i) {
return $i++;
}, $file_contents);
The m (multiline) flag is important - it will force our pattern to match # at the start of any line, not just the first.
I think you have to iterate over all the lines and replace the hash one by one. Of course, you can use some preg_replace as well to only replace the # at the line beginning: https://www.php.net/manual/en/function.preg-replace.php
$result = '';
$handle = fopen("data.txt", "r");
$i = 1;
if ($handle) {
while (($line = fgets($handle)) !== false) {
$content .= str_replace('#', $i++,$line) . "\n";
}
fclose($handle);
} else {
// error opening the file.
}
file_put_contents('data.txt', $result);
$path_to_file = 'data.txt';
$what_to_replace = '#';
$i = 1; // initial count
$file_contents = file_get_contents($path_to_file);
$lines = explode(PHP_EOL, $file_contents);
$new_lines = [];
foreach ($lines as $line) {
if (strpos($line, '#') !== false) {
$new_lines[] = str_replace('#', $i, $line);
$i++;
} else {
$new_lines[] = $line;
}
}
file_put_contents($path_to_file, implode(PHP_EOL, $new_lines));
We can split the text line-by-line, then process each line individually, looking for a # at the start of the line & modifying the output in those cases.
The preg_replace_callback approach is better than this one, IMO.
$text = file_get_contents(...);
$lines = explode("\n", $text); // split by unix-style line break
$out = []; // For storing the modified lines
$i=0;
foreach ($lines as $line){
if (substr($line,0,1)=='#'){
//replace the first character & increment the counter if line starts with #
$i++;
$line = $i.substr($line,1);
}
//append the SOMETIMES modified line to the output
$out[] = $line;
}
// convert array of lines to string
$fixedText = implode("\n", $out);
See https://stackoverflow.com/a/28725803/802469 for a more robust version of the explode("\n", $text) line.
Personally, I like the $out = []; ...; implode(...) approach. I find it easier to work with & to visualize in my mind. Using an $out = ""; $out .= $line."\n"; approach would work just as well. I suspect any performance increase from going with string would be negligible, but might lower your carbon footprint a small amount.
If you have serious performance/resource concerns (extremely large files) then the fopen()/while fgets() approach would be better, and fopen/fwrite() could be used to append each output line to a file without using up memory for an output string.
Solved on 2 steps:
Get the lines: https://stackoverflow.com/a/51350572/8524395
Remove the lines after getting them: https://stackoverflow.com/a/51377052/8524395
I have a large file, I want to take 1000 lines from the end of this file, then remove them.
I am currently using this:
function deleteLineInFile($file,$string)
{
$i=0;
$array=array();
$read = fopen($file, "r") or die("can't open the file");
while(!feof($read)) {
$array[$i] = fgets($read);
++$i;
}
fclose($read);
$write = fopen($file, "w") or die("can't open the file");
foreach($array as $a) {
if(!strstr($a,$string)) fwrite($write,$a);
}
fclose($write);
}
$goods = '';
$file = file("../products/".$PidFileName);
for ($i = max(0, count($file)-1001); $i < count($file); $i++) {
$goods = $goods.$file[$i] . '<br />';
deleteLineInFile("../products/".$PidFileName, $file[$i]);
}
I want to save the lines which I got in $goods
However, it times out because of the file size.
If you want to get N lines from EOF, you can use SPLFileObject (added in PHP 5.1):
$num_to_cut = 1000; // must be an integer and not a string
$new_file = new SplFileObject("limited_test.txt", "w");
$old_file = new SplFileObject('test.txt');
// here we get count of lines: go to EOF and get line number
$old_file->seek($old_file->getSize());
$linesTotal = $old_file->key()+1;
// and write data to new file
foreach( new LimitIterator($old_file, $linesTotal-$num_to_cut) as $line) {
$new_file->fwrite($line);
}
To remove the lines after getting them from a LARGE file:
The best way to do that is to use sed | But if you don't have access to use the exec() function then this is a function that you can use.
function replace_file($path, $string, $replace)
{
set_time_limit(0);
if (is_file($path) === true)
{
$file = fopen($path, 'r');
$temp = tempnam('./', 'tmp');
if (is_resource($file) === true)
{
while (feof($file) === false)
{
file_put_contents($temp, str_replace($string, $replace, fgets($file)), FILE_APPEND);
}
fclose($file);
}
unlink($path);
}
return rename($temp, $path);
}
Source of the function: https://stackoverflow.com/a/2159135/8524395
To remove the line use it like that:
replace_file('myfile.txt', 'RemoveThisPlease', '');
If you used MrSmile's answer to get the lines, then replace "RemoveThisPlease" with $line
I have an application which needs to open the file, then find string in it, and print a line number where is string found.
For example, file example.txt contains few hashes:
APLF2J51 1a79a4d60de6718e8e5b326e338ae533 EEQJE2YX
66b375b08fc869632935c9e6a9c7f8da O87IGF8R
c458fb5edb84c54f4dc42804622aa0c5 APLF2J51 B7TSW1ZE
1e9eea56686511e9052e6578b56ae018 EEQJE2YX
affb23b07576b88d1e9fea50719fb3b7
So, I want to PHP search for "1e9eea56686511e9052e6578b56ae018" and print out its line number, in this case 4.
Please note that there are will not be multiple hashes in file.
I found a few codes over Internet, but none seem to work.
I tried this one:
<?PHP
$string = "1e9eea56686511e9052e6578b56ae018";
$data = file_get_contents("example.txt");
$data = explode("\n", $data);
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $string) >= 0) {
die("String $string found at line number: $line");
}
}
?>
It just says that string is found at line 0.... Which is not correct....
Final application is much more complex than that...
After it founds line number, it should replace string which something else, and save changes to file, then goes further processing....
Thanks in advance :)
An ultra-basic solution could be:
$search = "1e9eea56686511e9052e6578b56ae018";
$lines = file('example.txt');
$line_number = false;
while (list($key, $line) = each($lines) and !$line_number) {
$line_number = (strpos($line, $search) !== FALSE) ? $key + 1 : $line_number;
}
echo $line_number;
A memory-saver version, for larger files:
$search = "1e9eea56686511e9052e6578b56ae018";
$line_number = false;
if ($handle = fopen("example.txt", "r")) {
$count = 0;
while (($line = fgets($handle, 4096)) !== FALSE and !$line_number) {
$count++;
$line_number = (strpos($line, $search) !== FALSE) ? $count : $line_number;
}
fclose($handle);
}
echo $line_number;
function get_line_from_hashes($file, $find){
$file_content = file_get_contents($file);
$lines = explode("\n", $file_content);
foreach($lines as $num => $line){
$pos = strpos($line, $find);
if($pos !== false)
return $num + 1
}
return false
}
get_line_from_hashes("arquivo.txt", "asdsadas2e3xe3ceQ#E"); //return some number or false case not found.
If you need fast and universal solution that working also for finding line number of multiline text in file, use this:
$file_content = file_get_contents('example.txt');
$content_before_string = strstr($file_content, $string, true);
if (false !== $content_before_string) {
$line = count(explode(PHP_EOL, $content_before_string));
die("String $string found at line number: $line");
}
FYI Works only with PHP 5.3.0+.
$pattern = '/1e9eea56686511e9052e6578b56ae018/';
if (preg_match($pattern, $content, $matches, PREG_OFFSET_CAPTURE)) {
//PREG_OFFSET_CAPTURE will add offset of the found string to the array of matches
//now get a substring of the offset length and explode it by \n
$lineNumber = count(explode("\n", substr($content, 0, $matches[0][1])));
}
If the file is not extremely large then just read the file into an array file, search for the word preg_grep, get the index key for that line and add 1 since the array starts at 0:
$string = "1e9eea56686511e9052e6578b56ae018";
echo key(preg_grep("/$string/", file("example.txt"))) + 1;
I found this to work great and be very efficient; Simply explode the file by each line and search through the array for your search terms like so:
function getLineNum($haystack, $needle){
# Our Count
$c = 1;
# Turn our file contents/haystack into an array
$hsarr = explode("\n", $haystack);
# Iterate through each value in the array as $str
foreach($hsarr as $str){
# If the current line contains our needle/hash we are looking for it
# returns the current count.
if(strstr($str, $needle)) return $c;
# If not, Keep adding one for every new line.
$c++;
}
# If nothing is found
if($c >= count($hsarr)) return 'No hash found!';
}
EDIT: Looking through the other answers, I realize that Guilherme Soares had a similar approach but used strpos, which in this case doesnt work. So I made a few alterations with his idea in mind here:
function getLineNum($haystack, $needle){
$hsarr = explode(PHP_EOL, $haystack);
foreach($hsarr as $num => $str) if(strstr($str, $needle)) return $num + 1;
return 'No hash found!';
}
Live Demo: https://ideone.com/J4ftV3
I have a text file and in it i want to only read the lines that start with an r then a space.
I have tried strpos but it does not seem to work.
$r="r ";
$file = file_get_contents('cached-consensus', true);
$n = explode("\n", $file);
foreach($n as $line){
$pos= strpos($line,$r);
echo $pos;}
Use this:
$file = file_get_contents('cached-consensus', true);
$n = explode("\n", $file);
foreach($n as $line){
if(0 === strpos($line, "r ")){
// do whatever you want with the line
}
}
This checks that $line starts with 'r '. Currently you're just echoing the position of the string (this should be 0).
I have a ID.txt file that looks like this:
"http://something.net/something-ak/41389_718783565_1214898307_q.jpg"
"http://something.net/something-ak/372142_106502518141813_1189943482_q.jpg"
and so on
I want to use PHP to open the file and remove everything before the first " _ " and everything after the second " _ " so I wind up with this:
718783565
106502518141813
and so on
Thing is I don't really know how to do that.
This is what I have so far:
<?PHP
$file_handle = fopen("ID.txt", "rb");
while (!feof($file_handle) ) {
$line_of_text = fgets($file_handle);
$parts = explode('\n', $line_of_text);
// Remove everything before the first "_" and everything after the last "_".
// echo the line
}
fclose($file_handle);
?>
Can someone help me fille in the blanks?
This is what I would do, although a regex might be shorter or more efficient:
$file_handle = fopen("ID.txt", "rb");
while (!feof($file_handle) )
{
$line_of_text = fgets($file_handle);
$parts = explode("\n", $line_of_text);
foreach ($parts as $str)
{
$str_parts = explode('_', $str); // Split string by _ into an array
array_shift($str_parts); // Remove first element
echo current($str_parts)."\n"; // echo current element and newline
// Same as $str_parts[0]
}
}
fclose($file_handle);
Demo: http://codepad.org/uFbVDtbR
Not a big deal, but $lines might be a better variable name there instead of $parts.
If you do need to write this back to the file, you can do this:
ob_start();
// code used above
$new_content = ob_get_clean();
file_put_contents("ID.txt", $new_content);
Relevant references:
http://php.net/manual/en/function.explode.php
http://www.php.net/manual/en/function.array-shift.php
http://php.net/manual/en/function.current.php
http://php.net/manual/en/function.file-put-contents.php
Just use file in a loop
$content = "";
foreach(file("ID.txt", FILE_SKIP_EMPTY_LINES) as $line){
$parts = explode('_', $line);
$content .= $parts[1] . "\n";
}
file_put_contents("ID.txt", $content);
If you want to achieve this by awk,
awk -F _ '{print $2}' ID.txt
Try this
preg_match('/(.*?)(.+?)(.*)/',$line,$matches);
$matches[2] will give the required string
This should work
<?php
// open files
$file_handle = fopen("ID.txt", "rb");
$new_file_handle = fopen("ID2.txt", "wb");
while (!feof($file_handle) ) {
$str = fgets($file_handle);
$start = strpos($str, '_'); // find first "_"
$end = strpos($str, '_', $start + 1); // find next "_"
$newstr = substr($str, $start + 1, $end - $start - 1) . "\n";
fputs($new_file_handle, $newstr);
}
// close files
fclose($file_handle);
fclose($new_file_handle);
// rename
rename("ID2.txt", "ID.txt");
$TXT = file_get_contents(__DIR__.'/in.txt');
$NewTXT = preg_replace('~^.+/[0-9]+_([0-9]+)_.+?$~mi', '$1', $TXT);
file_put_contents(__DIR__.'/out.txt', $NewTXT);
Just rename the .txt files accordingly.