我正在尝试解决一个人为的 PHP 任务/挑战,其中需要逐行遍历文本文件,并且如果方括号外部的回文在方括号内部具有倒置版本,则需要累积计算 3 个字母的回文。 回文的第二个字母必须与回文的第一个和第三个字母不同。 挑战/作业是指包含符合条件的回文作为“CrazyID”的行。
输入文件仅包含小写字母和方括号。 打开的大括号总是在同一行中关闭,并且没有嵌套的大括号表达式。 完整文件可以在此处查看:输入文件链接
方括号外部的限定回文可能出现在方括号内部的倒回文之前或之后。
以下是一些简化的输入行,可帮助解释逻辑:
示例行 | 数 | 原因 |
---|---|---|
|
1 | (外部)& (内部) |
|
0 | 的第二个字母与第一个和第三个字母没有不同 |
|
1 | (外部)& (内部) |
|
0 | 没有符合条件的 3 字母回文 |
|
1 | (外部)& 内部AND (外部)& (内部) |
|
1 | (外侧两次)和 (内侧) |
|
1 | (外部)和 (内部,不在紧邻的大括号中) |
PHP 程序应仅输出一个整数值,表示在 .txt 文件中找到的有效 CrazyID(包含至少一个合格回文的行)的总数。
经过不断的努力,我最新的编码尝试从2000行的txt文件中正确输出了231,但我会理解是否有更简洁或更有效的方法。
// Function to check if a inside_parts contains a HPH ( or BAB, or UVU) pattern
function containsHPH($inside_parts, $phpPatterns) {
foreach ($phpPatterns as $pattern) { //looping on each collected sequence code/pattern
$hph = $pattern[1] . $pattern[0] . $pattern[1]; //creating vice versa sequence code/pattern
if (strpos($inside_parts, $hph) !== false) { //check if it is exist in brackets
return true; //if found return true
}
}
return false; //patter not found in bracket
}
// Read the Puzzle Input file
$inputFile = 'puzzle_input.txt';
$file_lines = file($inputFile);
$validCrazyIDCount = 0;
foreach ($file_lines as $each_line) { //looping on file to fetch each line
preg_match_all('/\[([^\]]+)\]/', $each_line, $inside_brackets); //all string inside square bracket
preg_match_all('/([^\[\]]+)/', preg_replace('/\[[^\]]+\]/', ' ', $each_line), $outside_brackets); //all string outside square bracket separated by space
// Flatten the arrays
$inside_parts = implode(' ', $inside_brackets[1]); //0th array having square bracket and 1st array having plain text. so taking 1st array value
$outside_parts = implode(' ', $outside_brackets[0]); //all arrays are same, so taking 0th means first array value and convert into string
// Find PHP patterns outside the brackets
$phpPatterns = [];
$words = explode(' ', trim($outside_parts)); //outside string to each line array
//to check if a string contains a PHP (or ABA, or VUV) pattern
foreach ($words as $word) { //fetch each word from each lines all words
$len = strlen($word); //calculate length of word
for ($i = 0; $i < $len - 2; $i++) {
if ($word[$i] === $word[$i + 2] && $word[$i] !== $word[$i + 1]) { //match first and third letter && first letter does not match with second (to avoid AAA)
$phpPatterns[] = $word[$i] . $word[$i + 1] . $word[$i + 2]; //collect sequence code/pattern in array
}
}
}
// Check for corresponding HPH patterns inside the brackets
if (!empty($phpPatterns) && containsHPH($inside_parts, $phpPatterns)) { //if array contains data && check its vice versa string exists
$validCrazyIDCount++; //if found, increment the count
}
}
// Output the total number of validated CrazyIDs
echo $validCrazyIDCount; //output is 231
因为只需 1 个合格的回文就可以将一行视为有效(计数器),因此无需使用前瞻来在单行中进行多个匹配。
捕获第一个字母,捕获下一个字母并确保它与前一个字母不同,然后捕获下一个字母并确保它与第一个字母相同 - 这将验证第一个出现的回文。
然后捕获下一个出现的方括号(左大括号或右大括号,无论是哪个)。 然后在同一捕获的大括号之前的行中消耗零个或多个字符。 这确保了倒置回文出现在与原始回文相反的“支撑”段中(内部大括号 -> 外部大括号或外部大括号 -> 内部大括号)。
最后匹配所需段内的倒回文。
下面的模式中的几个捕获组不是必需的,但已包含在内是为了使行为更加清晰。 最低限度的捕获组将是第一个字母、第二个字母和“下一个出现的大括号”,
\K
也可以省略。
代码:(演示)
$pattern = '/
([a-z]) #capture group 1, a letter
(?!\1) #second letter cannot be the same as capture group 1
((?1)) #capture group 2, a different letter
(\1) #capture group 3, the repeated first letter
[^[\]\n]* #match any trailing non-braces and non-newlines
([[\]]) #capture group 4, the next occurring brace
(?:.*\4)* #match a subsequent captured brace
[^[\]\n]* #match zero or more non-braces and non-newlines
(\2) #capture (for sake of observability) group 2 letter
(\1) #capture (for sake of observability) group 1 letter
(\2) #capture (for sake of observability) group 2 letter
.* #consume the rest of the line for efficiency
\K #forget the fullstring match to keep output clean
/x'; #x means ignore whitespaces to allow for pattern comments
echo preg_match_all(
$pattern,
file_get_contents('puzzle_input.txt'),
$m, // only needed if calling var_export() below
PREG_SET_ORDER // only needed if calling var_export() below
);
// var_export($m); // if you want to see the captured characters
使用 2000 行示例输入,我的脚本仅通过调用
file_get_contents()
和 preg_match_all()
即可找到 231 行合格行。 (PHPize 演示)