I\'m using PHP\'s preg_match_all() to search a string imported using file_get_contents(). The regex returns matches but I would like to know at which line number those matches a
//Keep it simple, stupid
$allcodeline = explode(PHP_EOL, $content);
foreach ( $allcodeline as $line => $val ) :
if ( preg_match("#SOMEREGEX#i",$val,$res) ) {
echo $res[0] . '!' . $line . "\n";
}
endforeach;
Late to the game but I needed this functionality today and I realized that @Javier's and @iguito's answers could be combined into a simple solution. I also replaced the check for \n
with PHP_EOL
for my use case:
// Get your matches
preg_match_all( '[YOUR REGEX HERE]', $data, $matches, PREG_OFFSET_CAPTURE );
// This is my loop format, yours may need to be different
foreach ( $matches[0] as $match ) {
// Get the line number for the current match
list( $before ) = str_split( $data, $match[1] );
$line_number = substr_count( $before, PHP_EOL ) + 1;
echo $line_number;
}
$data = "Abba
Beegees
Beatles";
preg_match_all('/Abba|Beegees|Beatles/', $data, $matches, PREG_OFFSET_CAPTURE);
foreach (current($matches) as $match) {
$matchValue = $match[0];
$lineNumber = substr_count(mb_substr($data, 0, $match[1]), PHP_EOL) + 1;
echo "`{$matchValue}` at line {$lineNumber}\n";
}
Output
`Abba` at line 1
`Beegees` at line 2
`Beatles` at line 3
(check your performance requirements)
You have got a couple options, but none are "simple":
a) exec()
and use the system grep
command, which can report line numbers:
exec("grep -n 'your pattern here' file.txt", $output);`
b) Slurp in the file using file_get_contents()
, split it into an array of lines, then use preg_grep()
to find the matching lines.
$dat = file_get_contents('file.txt');
$lines = explode($dat, "\n");
$matches = preg_grep('/your pattern here/', $lines);
c) Read the file in line-sized chunks, keep a running line count, and do your pattern match on each line.
$fh = fopen('file.txt', 'rb');
$line = 1;
while ($line = fgets($fh)) {
if (preg_match('/your pattern here/', $line)) {
... whatever you need to do with matching lines ...
}
$line++;
}
Each has its ups and downs
a) You're invoking an external program, and if your pattern contains any user-supplied data, you're potentially opening yourself up to the shell equivalent of an SQL injection attack. On the plus side, you don't have to slurp in the entire file and will save a bit on memory overhead.
b) You're safe from shell injection attacks, but you have to slurp in the entire file. If your file is large, you'll probably exhaust available memory.
c) You're invoking a regex every line, which would have significant overhead if you're dealing with a large number of lines.