英文:
Add year function boolean and replace 3-letter month with its month number in an array of strings
问题
以下是代码部分的翻译:
$arr = [
// 如果没有1月份的记录,那么后续的所有记录都属于当前年份
"Dec 23 21:37:56 你好",
"Jan 12 02:08:23 你好",
"Jan 16 17:34:33 你好",
"Feb 4 12:21:09 你好",
"Mar 19 17:07:26 你好",
"Apr 1 00:00:03 你好",
"Apr 12 23:07:39 你好",
"May 21 04:09:34 你好",
"Jun 7 23:34:56 你好",
"Jul 1 14:45:34 你好",
"Aug 13 11:37:23 你好",
"Sep 29 07:36:03 你好",
"Oct 30 09:01:00 你好",
"Nov 10 11:00:03 你好",
"Dec 25 21:47:51 你好"
];
function setYear()
{
global $arr, $y;
$first = explode(' ', $arr[array_key_first($arr)]);
// 如果第一行不以"01"开始,那么它属于上一年。
if (!in_array('01', $first)) {
$y = date("Y", strtotime("-1 year"));
} else {
$y = date("Y");
}
return $y;
}
$arr = preg_replace_callback(
'/^(\w+)\s+(\d+)\s/',
function ($matches) {
global $y;
$yy = setYear($y);
return date($yy . ' m d', strtotime($matches[0] . ' ' . date("Y"))) . ' ';
},
$arr
);
echo '<pre>';
print_r($arr);
echo '</pre>';
希望这对你有帮助。如果有其他问题,请随时提出。
英文:
Background information:
- The log file is copied and read out at regular intervals.
- Log file lines do not have a year specification.
- Months are continuous.
- Before January is always the previous year.
If January lines do not appear in the log file, then it is only about the current year. Example:
- 2023 mar,
- 2023 apr,
- 2023 may,
- 2023 jun
If January occurs one or more times in the month cycle, then the current year is from the beginning of the last occurrence (January). Example:
- 2021 nov,
- 2021 dec,
- 2021 dec
- 2022 jan, // new year
- 2022 jan,
- 2022 feb,
- ...
- 2022 dec,
- 2023 jan, // new year, last jan = actual year
- 2023 jan,
- 2023 feb,
- ...
Code:
Recognize which year it is based on the 3-letters and lines and add the correct year to each line.
$arr = [
// without first Dec, Jan and Jan lines:
// all subsequent lines are the current year
"Dec 23 21:37:56 hello",
"Jan 12 02:08:23 hello",
"Jan 16 17:34:33 hello",
"Feb 4 12:21:09 hello",
"Mar 19 17:07:26 hello",
"Apr 1 00:00:03 hello",
"Apr 12 23:07:39 hello",
"May 21 04:09:34 hello",
"Jun 7 23:34:56 hello",
"Jul 1 14:45:34 hello",
"Aug 13 11:37:23 hello",
"Sep 29 07:36:03 hello",
"Oct 30 09:01:00 hello",
"Nov 10 11:00:03 hello",
"Dec 25 21:47:51 hello"
];
Create a function to find the years.
function setYear()
{
global $arr, $y;
$first = explode(' ', $arr[array_key_first($arr)]);
// if the 1st line doesn't start with Jan, then it's the previous year.
if (!in_array('01', $first)) {
$y = date("Y", strtotime("-1 year"));
} else {
$y = date("Y");
}
return $y;
}
Convert date year and month integer
$arr = preg_replace_callback(
'/^(\w+)\s+(\d+)\s/',
function ($matches) {
global $y;
$yy = setYear($y);
return date($yy . ' m d', strtotime($matches[0] . ' ' . date("Y"))) . ' ';
},
$arr
);
echo '<pre>';
print_r($arr);
echo '</pre>';
Unexpected result:
Array
(
[0] => 2022 12 23 21:37:56 hello
[1] => 2022 01 12 02:08:23 hello
[2] => 2022 01 16 17:34:33 hello
[3] => 2022 02 04 12:21:09 hello
[4] => 2022 03 19 17:07:26 hello
// ...
[9] => 2022 11 10 11:00:03 hello
[10] => 2022 12 25 21:47:51 hello
)
Expected result:
Array
(
[0] => 2023 12 23 21:37:56 hello
[1] => 2022 01 12 02:08:23 hello
[2] => 2022 01 16 17:34:33 hello
[3] => 2022 02 04 12:21:09 hello
[4] => 2022 03 19 17:07:26 hello
// ...
[9] => 2022 11 10 11:00:03 hello
[10] => 2022 12 25 21:47:51 hello
)
答案1
得分: 1
使用static
变量来替代将全局变量引入作用域的global
。static
关键字将确保先前迭代的声明被保留并且可访问。如果遇到或之前遇到了Jan
,则将标志设置为true
。直到标志设置为true
,从日期的年份中减去1年。
var_export(
preg_replace_callback(
'/^([a-z]{3}) +\d+/i',
function($m) {
static $encounteredJan = false;
$encounteredJan = $encounteredJan || $m[1] === 'Jan';
return date('Y m d', strtotime($m[0] . ($encounteredJan ? '' : ' -1 year')));
},
$arr
)
);
如果不能依赖数据集中存在Jan
,那么(假设永远不需要向前跳跃超过一年),只需检查当前月份是否小于上次遇到的月份。例如,从9月到4月(10到4),那么可以安全地假设年份应该增加/递增。
var_export(
preg_replace_callback(
'/^([a-z]{3}) +\d+/i',
function($m) {
static $lastMonthInt = 0;
static $year = null;
$year ??= date('Y', strtotime('-1 year'));
$currentMonthInt = date('n', strtotime($m[1]));
if ($currentMonthInt < $lastMonthInt) {
++$year;
}
$lastMonthInt = $currentMonthInt;
return "$year " . date('m d', strtotime($m[0]));
},
$arr
)
);
最终编辑:
为确保生成的最高年份是当前年份,使用array_reverse()
来处理数据,从最新的条目到最早的条目。将标准化的时间戳表达式与上一个时间戳进行比较。当当前时间戳大于上一个时间戳时,减小年份。处理完成后,在结果上调用array_reverse()
以恢复原始顺序。
var_export(
array_reverse(
preg_replace_callback(
'/^[a-z]{3} +\d+ \d\d:\d\d:\d\d/i',
function($m) {
static $lastStamp = null;
static $year = null;
$year ??= date('Y');
$currentStamp = date('m d H:i:s', strtotime($m[0]));
if ($currentStamp > ($lastStamp ?? $currentStamp)) {
--$year;
}
$lastStamp = $currentStamp;
return "$year $currentStamp";
},
array_reverse($arr)
)
)
);
英文:
Use a static
variable instead of bringing global variables into scope with global
. The static
keyword will ensure that the previous iterations' declaration is retained and is accessible. If Jan
is encountered or was encountered before, set the flag as true
. Until the flag is set to true
, subtract 1 year from the date's year.
Code: (Demo)
var_export(
preg_replace_callback(
'/^([a-z]{3}) +\d+/i',
function($m) {
static $encounteredJan = false;
$encounteredJan = $encounteredJan || $m[1] === 'Jan';
return date('Y m d', strtotime($m[0] . ($encounteredJan ? '' : ' -1 year')));
},
$arr
)
);
If you cannot rely on Jan existing in the dataset, then (assuming you never need to jump more than one year forward), just check if the current month is less than the last encountered month. If, say, going from Sep to Apr (10 to 4), then you can safely assume that the year should be increased/incremented.
Code: (Demo)
var_export(
preg_replace_callback(
'/^([a-z]{3}) +\d+/i',
function($m) {
static $lastMonthInt = 0;
static $year = null;
$year ??= date('Y', strtotime('-1 year'));
$currentMonthInt = date('n', strtotime($m[1]));
if ($currentMonthInt < $lastMonthInt) {
++$year;
}
$lastMonthInt = $currentMonthInt;
return "$year " . date('m d', strtotime($m[0]));
},
$arr
)
);
Final edit:
To ensure that the highest generated year is the current year, use array_reverse()
to process the data from latest entry to the earliest entry. Compare the standardized timestamp expression against the previous timestamp. When the current stamp is greater than the last, decrement the year. When finished processing, call array_reverse()
on the result to return it to its original order.
Code: (Demo)
var_export(
array_reverse(
preg_replace_callback(
'/^[a-z]{3} +\d+ \d\d:\d\d:\d\d/i',
function($m) {
static $lastStamp = null;
static $year = null;
$year ??= date('Y');
$currentStamp = date('m d H:i:s', strtotime($m[0]));
if ($currentStamp > ($lastStamp ?? $currentStamp)) {
--$year;
}
$lastStamp = $currentStamp;
return "$year $currentStamp";
},
array_reverse($arr)
)
)
);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论