#php #regex #date
#php #регулярное выражение #Дата
Вопрос:
Я пытаюсь проанализировать введенные пользователем строковые даты с помощью PHP. Мне нужно удалить все символы, отличные от этих двух допустимых категорий:
1) [0-9,./-] (numerals, comma, period, slash, and dash)
2) An array of acceptable words:
$monthNames=array(
"january"=>1,
"jan"=>1,
"february"=>2,
"feb"=>2
);
Я попробовал explode() для добавления символьных слов, а затем удалил каждый раздел, которого нет в массиве, но это привело к довольно беспорядку. Есть ли элегантный способ добиться этого?
Спасибо!
Комментарии:
1. Вы должны показать свой код, чтобы было более понятно, к чему вы стремитесь.
2. Используете ли вы встроенную в php функцию in_array()? php.net/manual/en/function.in-array.php
3.
strtotime()
php.net/manual/en/function.strtotime.php4. strtotime() требует определенного формата, эти пользователи вводят все, начиная с «12 января 1977 года», «12-1-1977», «1/12/1977» и «Turkiye». Я выделил около шести или семи вариантов, которые могут быть законными датами.
5. @ford: функция str_replace() примет массив в качестве аргумента, но только для элементов для замены! Я могу foreach с помощью in_array для фрагментов, но тогда у меня возникают проблемы с регулярным выражением для цифр, которые также нужно оставить. Вот почему я не вставлял код: похоже, с того направления, в котором я двигался, мало что можно было спасти, поэтому я надеялся услышать о более элегантном решении.
Ответ №1:
Вы могли бы использовать strtotime()
echo strtotime("now"), "n";
echo strtotime("10 September 2000"), "n";
echo strtotime(" 1 day"), "n";
echo strtotime(" 1 week"), "n";
echo strtotime(" 1 week 2 days 4 hours 2 seconds"), "n";
echo strtotime("next Thursday"), "n";
echo strtotime("last Monday"), "n";
Для проверки на сбой:
$str = 'Not Good';
// previous to PHP 5.1.0 you would compare with -1, instead of false
if (($timestamp = strtotime($str)) === false) {
echo "The string ($str) is bogus";
} else {
echo "$str == " . date('l dS of F Y h:i:s A', $timestamp);
}
Смотрите http://php.net/manual/en/function.strtotime.php
Также DateTime::createFromFormat()
может быть полезно.
Смотрите http://www.php.net/manual/en/datetime.createfromformat.php
Ответ №2:
Лучший способ избежать этого — сделать ввод даты формой с единственным допустимым параметром и отказаться от остальных.
Комментарии:
1. Это данные, которые вводились в течение многих лет. Это не новые данные.
Ответ №3:
Вы могли бы использовать регулярное выражение для сопоставления дат, вот очень упрощенное, элементарное:
preg_match('/((Jan|Feb|Dec|d{1,2})[ ./-]){2,2}d{1,4}/i', $str, $matches);
echo $matches[0];
Однако вам придется добавить другие месяцы.
Дополнительные идеи для бессонных ночей:
- запретить месяцы < 1 и > 12
- запретить январь Январь 2011
- запретить странные годы
- …
- удалите его и найдите хорошее 😉
Я бы выбрал двухэтапный подход:
- Извлеките что-то, что выглядит как дата
- Используйте встроенные функции времени, чтобы проверить, можно ли создать временную метку, которая имеет смысл из нее. Если вы не можете, выбросьте его.
Ответ №4:
Если можно с уверенностью предположить, что ваш массив $ MonthNames содержит менее 26 элементов, то работает следующее (хотя это определенно «взлом» — я предложу другой ответ, если смогу придумать что-то, что заслуживает названия «элегантный»):
<?php
$text = 'january 3 february 7 xyz';
print 'original string=[' . $text . "]n";
$monthNames = array(
'january' => 1,
'jan' => 1,
'february' => 2,
'feb' => 2
// ... presumably there are some more array elements here...
);
// Map each monthNames key to a capital letter:
$i = 65; // ASCII code for 'A'
$mmap = array();
foreach (array_keys($monthNames) as $m) {
$c = chr($i);
$mmap[$c] = $m;
$i = 1;
}
// Strip out capital letters first:
$text1 = preg_replace('/[A-Z] /', "", $text);
// Replace each month name with its letter:
$text2 = str_replace(array_keys($monthNames), array_keys($mmap), $text1);
// Filter out everything that is not allowed:
$text3 = preg_replace('/[^0-9,.-A-Z]/', "", $text2);
// Restore the original month names:
$text4 = str_replace(array_keys($mmap), array_keys($monthNames), $text3);
print 'filtered string=[' . $text4 . "]n";
?>
Примечания:
- Если у вас есть более 26 строк, которые нужно исключить из фильтрации, то вы можете написать код, чтобы использовать ту же идею, но IMO становится значительно сложнее сделать указанный код понятным людям (или мне, во всяком случае).
- Вы, конечно, можете настроить шаблон preg_replace(), чтобы оставить пробелы в покое, если вы решите, что они вам действительно нужны.
Комментарии:
1. Я не уверен, работает ли это безупречно: что произойдет, если входной строкой будет `3 января 7 февраля XYZ»?
2. Действительно, ваш пример демонстрирует недостающую часть логики: все заглавные буквы должны быть удалены перед шагом замены.
3. Изменен код — добавлен начальный шаг для удаления заглавных букв.
4. тогда хорошо: что произойдет, если входная строка равна
January 3 february 7
?5. @Cassy — Проблема, как было указано изначально, исключает «январь», поэтому у вас (правильно) останется «3 7 февраля». Теперь вы можете утверждать, что массив $MonthNames является неполным — что так и есть. В этом случае правильный результат будет зависеть от того, был ли включен «Январь» в качестве ключа.