2011-01-19 83 views
11

我使用PHP的preg_match_all()來搜索使用file_get_contents()導入的字符串。正則表達式返回匹配,但我想知道在哪個行號找到這些匹配。實現這一目標的最佳技術是什麼?從preg_match_all()獲取行號

我可以讀取文件作爲數組,併爲每一行執行正則表達式,但問題是我的正則表達式匹配回車(新行)的結果。

+1

我要扔了一個猜測,說你可能不能夠爲此使用`preg_match_all`。 – drudge 2011-01-19 01:31:46

+0

preg_split和結果中的行數?這聽起來很蠢,現在我說了。 – scragz 2011-01-19 01:32:19

+0

我沒有看到任何簡單的方法來完成你想要做的事... – 2011-01-19 01:36:21

回答

8

好吧,它有點晚了,也許你alrady解決了這個問題,但我必須這樣做,它很簡單。 使用PREG_OFFSET_CAPTURE標誌preg_match將返回匹配的字符位置。 讓我們假設$ charpos,所以

list($before) = str_split($content, $charpos); // fetches all the text before the match 

$line_number = strlen($before) - strlen(str_replace("\n", "", $before)) + 1; 

voilá!

10

你不能這樣做只有正則表達式。至少不乾淨。你能做些什麼來使用preg_match_all的PREG_OFFSET_CAPTURE標誌並對整個文件進行後分析。

我的意思是你有匹配的字符串數組,並開始偏移每個字符串後僅數\r\n\n\r有多少文件開始,每場比賽的偏移之間。匹配的行號將是不同EOL終止符的數量(\r\n | \n | \r)加上1

1

我想,首先,你需要閱讀$字符串到一個數組,每個元素代表每一行,也不要這個樣子:

$List=file($String); 
for($i=0;$i<count($List),$i++){ 
if(preg_match_all()){;//your work here 
echo $i;//echo the line number where the preg_match_all() works 
} 
} 
+0

我想你錯過了我的問題的這一部分:我可以讀取文件作爲數組,併爲每一行執行正則表達式,但問題是我的正則表達式匹配回車(新行)的結果。 – bart 2017-07-31 20:00:35

2

你有一對夫婦的選擇,但沒有是 「簡單」:

一個)exec()和使用該系統grep命令,該命令可以報告行號:使用在文件中

exec("grep -n 'your pattern here' file.txt", $output);` 

b)中啜食,將其拆分爲一行數組,然後使用preg_grep()來查找匹配的行。

$dat = file_get_contents('file.txt'); 
$lines = explode($dat, "\n"); 
$matches = preg_grep('/your pattern here/', $lines); 

c)以行大小塊讀取文件,保持行數,並在每行上進行模式匹配。

$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++; 
} 

每個人都有其跌宕起伏

一)你調用外部程序,如果你的模式包含任何用戶提供的數據,你可能自己開到外殼當量一個SQL注入攻擊。另一方面,你不必在整個文件中啜泣,並且會節省一些內存開銷。

b)您可以安全地使用shell注入攻擊,但是您必須在整個文件中啜泣。如果你的文件很大,你可能會耗盡可用的內存。

c)你每行調用一個正則表達式,如果你處理大量的行,這會產生大量的開銷。

0

您可以使用preg_match_all查找每個換行的偏移量,然後將它們與您已有的偏移量進行比較。

// read file to buffer 
$data = file_get_contents($datafile); 

// find all linefeeds in buffer  
$reg = preg_match_all("/\n/", $data, $lfall, PREG_OFFSET_CAPTURE); 
$lfs = $lfall[0]; 

// create an array of every offset 
$linenum = 1; 
$offset = 0;  
foreach($lfs as $lfrow) 
{ 
    $lfoffset = intval($lfrow[1]); 
    for(; $offset <= $lfoffset; $offset++) 
     $offsets[$offset] = $linenum; // offset => linenum 
    $linenum++; 
} 
0

這可行,但在每一行都會執行新的preg_match_all,這可能會非常昂貴。

$file = file.txt; 

$log = array(); 

$line = 0; 

$pattern = '/\x20{2,}/'; 

if(is_readable($file)){ 

    $handle = fopen($file, 'rb'); 

    if ($handle) { 

     while (($subject = fgets($handle)) !== false) { 

      $line++; 

      if(preg_match_all ($pattern, $subject, $matches)){ 

       $log[] = array(
        'str' => $subject, 
        'file' => realpath($file), 
        'line' => $line, 
        'matches' => $matches, 
       ); 
      } 
     } 
     if (!feof($handle)) { 
      echo "Error: unexpected fgets() fail\n"; 
     } 
     fclose($handle); 
    } 
} 

另外,您可以讀取該文件一旦喲得到的行號,然後對整個文件進行preg_match_all和catpure的匹配偏移。

$file = 'file.txt'; 
$length = 0; 
$pattern = '/\x20{2,}/'; 
$lines = array(0); 

if(is_readable($file)){ 

    $handle = fopen($file, 'rb'); 

    if ($handle) { 

     $subject = ""; 

     while (($line = fgets($handle)) !== false) { 

      $subject .= $line; 
      $lines[] = strlen($subject); 
     } 
     if (!feof($handle)) { 
      echo "Error: unexpected fgets() fail\n"; 
     } 
     fclose($handle); 

     if($subject && preg_match_all ($pattern, $subject, $matches, PREG_OFFSET_CAPTURE)){ 

      reset($lines); 

      foreach ($matches[0] as $key => $value) { 

       while(list($line, $length) = each($lines)){ // continues where we left off 

        if($value[1] < $length){ 

         echo "match is on line: " . $line; 

         break; //break out of while loop; 
        } 
       } 
      } 
     } 
    } 
}} 
0
//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; 
1
$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"; 
} 

輸出

`Abba` at line 1 
`Beegees` at line 2 
`Beatles` at line 3 

(請檢查您的性能需求)