首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 統計文本文件每行出現最多字符:fopen、fgets、count_chars 組合實戰

     編輯:PHP 綜合知識

核心函數組合

function analyzeLineDominantChars(string $filePath): Generator {
    $handle = fopen($filePath, 'r');
    if (!$handle) throw new Exception("無法打開文件: $filePath");
    
    try {
        while (($line = fgets($handle)) !== false) {
            $line = rtrim($line, "\r\n"); // 保留行內空格,去除換行符
            if ($line === '') {
                yield ['line' => '', 'char' => null, 'count' => 0];
                continue;
            }
            
            // count_chars 模式 1: 返回 [字符 ASCII 碼 => 出現次數]
            $freq = count_chars($line, 1);
            if (empty($freq)) {
                yield ['line' => $line, 'char' => null, 'count' => 0];
                continue;
            }
            
            // 降序排序,保持鍵關聯
            arsort($freq);
            $topCharCode = key($freq);
            $topCount = current($freq);
            
            yield [
                'line' => $line,
                'char' => chr($topCharCode),
                'char_code' => $topCharCode,
                'count' => $topCount,
                'line_length' => strlen($line),
            ];
        }
    } finally {
        fclose($handle);
    }
}

// 使用示例
foreach (analyzeLineDominantChars('test.txt') as $result) {
    printf("行: %-30s | 高頻字符: '%s' (ASCII:%d) | 次數: %d\n", 
        mb_substr($result['line'], 0, 30), 
        $result['char'] ?? '空', 
        $result['char_code'] ?? 0, 
        $result['count']
    );
}

測試數據與輸出

# test.txt 內容
Welcome to our website jb51.net
www.jb51.net
php asp java jsp

# 輸出
行: Welcome to our website jb51.ne  | 高頻字符: 'e' (ASCII:101) | 次數: 5
行: www.jb51.net                      | 高頻字符: 'w' (ASCII:119) | 次數: 3
行: php asp java jsp                  | 高頻字符: 'p' (ASCII:112) | 次數: 4

count_chars 四種模式詳解

模式返回值用途
0256 長度數組,索引為 ASCII 碼,值為出現次數完整頻率統計,含 0 次字符
1關聯數組 [ASCII碼 => 次數],僅包含出現過的字符最常用,配合 arsort 找高頻
2同模式 0,但僅包含未出現的字符 (次數為 0)檢測缺失字符集
3字符串,由所有出現過的字符組成 (去重、按 ASCII 排序)快速獲取字符集
4字符串,由所有未出現過的字符組成補集字符集

進階擴展:統計單詞/中文字符頻率

// 單詞頻率 (英文)
function lineTopWord(string $line): ?array {
    preg_match_all('/\b\w+\b/', strtolower($line), $matches);
    if (empty($matches[0])) return null;
    $freq = array_count_values($matches[0]);
    arsort($freq);
    return [key($freq), current($freq)];
}

// 中文字符頻率 (需 mbstring)
function lineTopMbChar(string $line): ?array {
    $chars = [];
    $len = mb_strlen($line, 'UTF-8');
    for ($i = 0; $i < $len; $i++) {
        $char = mb_substr($line, $i, 1, 'UTF-8');
        if (preg_match('/\p{Han}/u', $char)) { // 僅統計漢字
            $chars[$char] = ($chars[$char] ?? 0) + 1;
        }
    }
    if (empty($chars)) return null;
    arsort($chars);
    return [key($chars), current($chars)];
}

大文件處理優化

  • 生成器模式:逐行處理,內存常數級,適合 GB 級日志文件
  • 並行處理:使用 pcntl_fork 或 Swoole 進程池,按文件大小分塊 (需固定行長或預掃描行偏移)
  • 流式過濾:stream_filter_append($handle, 'custom_filter') 邊讀邊統計,避免 PHP 循環開銷
  • 內存映射:mmap (需擴展) 將文件映射到內存,極速隨機訪問

實戰場景:日志異常檢測

function detectAnomalyLines(string $logFile, float $threshold = 0.8): Generator {
    foreach (analyzeLineDominantChars($logFile) as $stat) {
        if ($stat['line_length'] > 0) {
            $ratio = $stat['count'] / $stat['line_length'];
            if ($ratio > $threshold) {
                yield $stat; // 疑似重複字符攻擊、編碼錯誤、二進制混入
            }
        }
    }
}
// 使用:foreach (detectAnomalyLines('/var/log/nginx/access.log') as $anomaly) { alert($anomaly); }
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved