Проверьте строку для символов в алфавитном порядке
Это кажется настолько очевидным, но я не могу найти способ сделать это.
Я думаю, что есть даже регулярная функция PHP, чтобы сделать это, но даже тот, который остается хорошо скрытым после 1,5 часов интенсивных поисков Google.
Что я хочу
- Функция, которая принимает строку как входную.
- Проверяет эту строку на количество раз, когда она имеет порядковые последовательности в алфавитном порядке из более чем 3 символов:
- возвращает true, если найдена последовательность из более чем 3.
Пример
"youlookgreatbcdetoday" = > имеет в нем "bcde"... так что нужно вернуть true |
"youlookgreatklmtoday" = > имеет только "klm" в нем... так что он должен вернуть false
"youlookgreattoday" = > не имеет алфавитно упорядоченных последовательностей, поэтому возвращает false
Возможная операция
- проверка прочности пароля
- wordgame
- ...
Отказ от ответственности: Хотелось бы, чтобы у меня уже был какой-то код, чтобы показать вам, но у меня в буквальном смысле ничего нет.
Единственное, что я мог придумать, это разбить строку на массив и сделать магию на массиве... но даже тогда я застрял.
Надеюсь, что один из вас спасет меня:)
Ответы
Ответ 1
Итак, давайте начнем с тривиальной реализации, используя цикл и счетчик (только для увеличения):
function hasOrderedCharactersForward($string, $num = 4) {
$len = strlen($string);
$count = 0;
$last = 0;
for ($i = 0; $i < $len; $i++) {
$current = ord($string[$i]);
if ($current == $last + 1) {
$count++;
if ($count >= $num) {
return true;
}
} else {
$count = 1;
}
$last = $current;
}
return false;
}
Итак, как это работает? В принципе, он прокручивается и проверяет, является ли символ ord
(ascii) символа более чем тем, который был перед ним. Если это так, он увеличивает параметр count. В противном случае он устанавливает значение 1 (поскольку мы уже обработали этот символ). Тогда, если $count
все больше или равно запрашиваемому числу, мы знаем, что мы нашли последовательность и можем вернуться...
Итак, теперь давайте проверим в обоих направлениях:
function hasOrderedCharacters($string, $num = 4) {
$len = strlen($string);
$count = 0;
$dir = 1;
$last = 0;
for ($i = 0; $i < $len; $i++) {
$current = ord($string[$i]);
if ($count == 1 && $current == $last - 1) {
$count++;
$dir = -1;
if ($count >= $num) {
return true;
}
} elseif ($current == $last + $dir) {
$count++;
if ($count >= $num) {
return true;
}
} else {
$count = 1;
$dir = 1;
}
$last = $current;
}
return false;
}
Теперь он вернет true для abcd
и dcba
...
Теперь здесь гораздо более простое решение:
function hasOrderedCharactersForward($string, $num = 4) {
$len = strlen($string) + 1;
$array = array_map(
function($m) use (&$len) {
return ord($m[0]) + $len--;
},
str_split($string, 1)
);
$str = implode('_', $array);
$regex = '#(^|_)(\d+)' . str_repeat('_\2', $num - 1) . '(_|$)#';
return (bool) preg_match($regex, $str);
}
И ты туда. Мы используем свойство, что если мы добавим уменьшающееся число в каждую позицию, последовательные последовательности будут отображаться как одно и то же число. И это точно, как это работает.
И здесь та же теория применяется к обоим направлениям:
function hasOrderedCharacters($string, $num = 4) {
$i = 0;
$j = strlen($string);
$str = implode('', array_map(function($m) use (&$i, &$j) {
return chr((ord($m[0]) + $j--) % 256) . chr((ord($m[0]) + $i++) % 256);
}, str_split($string, 1)));
return preg_match('#(.)(.\1){' . ($num - 1) . '}#', $str);
}
Ответ 2
Меньше цикла и если условие!
function alphacheck($str, $i=4)
{
$alpha = 'abcdefghijklmnopqrstuvwxyz';
$len = strlen($str);
for($j=0; $j <= $len - $i; $j++){
if(strrpos($alpha, substr($str, $j, $i)) !== false){
return true;
}
}
return false;
}
Ответ 3
<?php
function check($input, $length = 4)
{
$sequence = "abcdefghijklmnopqrstuvwxyz";
$sequence .= substr($sequence, 0, $length - 1);
// abcdefghijklmnopqrstuvwxyz is converted to abcdefghijklmnopqrstuvwxyzabc
for ($i = 0; $i < strlen($sequence) - $length; $i++) {
// loop runs for $i = 0...25
if (strpos($input, substr($sequence, $i, $length)) !== false) {
echo sprintf('"%s" contains "%s"' . PHP_EOL, $input, substr($sequence, $i, $length));
return true;
}
}
echo sprintf('"%s" is OK' . PHP_EOL, $input);
return false;
}
check("youlookgreatbcdetoday"); // "youlookgreatbcdetoday" contains "bcde"
check("youlookgreatklmtoday"); // "youlookgreatklmtoday" is OK
check("youlookgreattoday"); // "youlookgreattoday" is OK
check("youlookgreattodayza"); // "youlookgreattodayza" is OK
check("youlookgreattodayzab"); // "youlookgreattodayzab" contains "yzab"
Ответ 4
Вот что я придумал:
/**
* @param string $input Input string
* @param int $length Length of required sequence
*
* @return bool
*/
function look_for_sequence($input, $length) {
//If length of sequence is larger than input string, no sequence is possible.
if ($length > strlen($input)) {
return false;
}
//Normalize string, only lowercase
//(That because character codes for lowercase and uppercase are different).
$input = strtolower($input);
//We loop until $length characters before the end of the string, because after that,
//No match can be found.
for ($i = 0; $i < strlen($input) - $length; $i++) {
//Reset sequence counter
$sequence = 1;
//Character under inspection.
$current_character = ord($input[$i]);
//Let look forward, $length characters forward:
for ($j = $i + 1; $j <= $i + $length; $j++) {
$next_character = ord($input[$j]);
//If this next character is actually the sequencing character after the current
if ($next_character == $current_character+1) {
//Increase sequence counter
$sequence++;
//Reset the current character, and move to the next
$current_character = $next_character;
//If $length characters of sequence is found, return true.
if ($sequence >= $length) {
return true;
}
}
//If the next character is no sequencing,
//break this inner loop and continue to the next character.
else {
break;
}
}
}
return false;
}
var_dump(look_for_sequence("youlookgreatbcdetoday", 4));
Работал над любой строкой, которую я бросил на нее, и вы также можете выбрать, сколько символов вы хотите посчитать! Yey!
Ответ 5
Вы можете попробовать использовать PHP ord()
, чтобы получить каждое значение ASCII символа и выполнить итерацию по строке по каждому символу, сравнивая каждое значение с найти последовательности.
Это может помочь:
function checkForSequences($str, $minSequenceLength = 4) {
$length = strlen($str);
$sequenceLength = 1;
$reverseSequenceLength = 1;
for ($i = 1; $i < $length; $i++) {
$currChar = ord(strtolower($str[$i]));
$prevChar = ord(strtolower($str[$i - 1])) + 1;
if ($currChar == $prevChar) {
// we have two-letters back to back; increment the counter!
$sequenceLength++;
if ($sequenceLength == $minSequenceLength) {
// we've reached our threshold!
return true;
}
// reset the reverse-counter
$reverseSequenceLength = 1;
} else if ($currChar == ($prevChar - 2)) {
// we have two-letters back to back, in reverse order; increment the counter!
$reverseSequenceLength++;
if ($reverseSequenceLength == $minSequenceLength) {
// we've reached our threshold!
return true;
}
// reset the forward-counter
$sequenceLength = 1;
} else {
// no sequence; reset counter
$sequenceLength = 1;
$reverseSequenceLength = 1;
}
}
return false;
}
Что будет делать эта функция, она будет перебирать символ строки по символу. Он будет использовать ord()
, чтобы получить текущее значение ASCII-символа и сравнить его с предыдущим значением ASCII-символа. Если они находятся в последовательности, либо вперед, либо назад, он увеличивает счетчик. Когда счетчик достиг 4
, он возвращает true
!.
Это будет соответствовать прямой и обратной последовательности, а также игнорировать регистр. Таким образом, abcd
будет соответствовать, abcd
будет, а также DcBa
, среди любых других!
Ответ 6
Вот простое решение, которое я придумал:
function alphaCheck($str){
$array=str_split(strtolower($str));
$minMatchLength=3;
$check=array(ord($array[0]));
foreach($array as $letter){
$ascii=ord($letter);
if($ascii==end($check)+1){
$check[]=$ascii;
if(count($check)==$minMatchLength)
return true;
}else{
unset($check);
$check=array($ascii);
}
}
return false;
}
$str="abcdhello";
$str2="testing";
$str3="abdcefghi";
if(alphaCheck($str))
echo"STR GOOD";
if(alphaCheck($str2))
echo "STR2 GOOD";
if(alphaCheck($str3))
echo "STR3 GOOD";
Выход: STR GOOD и STR3 GOOD. $minMatchLength
- количество символов в строке, которое должно быть для того, чтобы функция вернула значение true. ( "тестирование" имеет "st", но длина равно 3, поэтому возвращает false.
ИЗМЕНИТЬ
Я обновил его, чтобы проверить "AbCdE", поскольку только один ord
не будет работать для этого.
Ответ 7
Непосредственное сравнение символов неявно использует значение ord(). Вот простой script, который можно настроить (в частности, для нечувствительности к регистру):
<?php
$string = "thisabcdef";
function hasSequence($string, $sequence_length = 3) {
$num_in_order = 0;
for($i = 1; $i < strlen($string); $i++) {
if($string[$i] > $string[$i-1]) {
$num_in_order++;
} else {
$num_in_order = 0;
}
if($num_in_order >= $sequence_length) {
return TRUE;
}
}
return FALSE;
}
if(hasSequence("testabcd")) {
echo "YUP";
} else {
echo "NOPE";
}
echo "\n";
Ответ 8
Может быть, упрощен? Если вы хотите нечувствительность к регистру, вы можете использовать stripos()
вместо этого.
function abc($test, $depth) {
$alpha = 'abcdefghijklmnopqrstuvwxyz';
$matches = 0;
$length = strlen($test);
while ($length--) {
$char = substr($test, $length, $depth);
if (strlen($char) == $depth && strpos($alpha, $char) !== false) {
$matches++;
}
if ($matches == $depth) return true;
}
return false;
}
http://codepad.org/tIySKnm4
И (кражи наблюдения IRCMaxwell) с strrev()
:
function abc($test, $depth) {
$alpha = 'abcdefghijklmnopqrstuvwxyz';
$matches = 0;
$length = strlen($test);
while ($length--) {
$char = substr($test, $length, $depth);
if (strlen($char) == $depth &&
(strpos($alpha, $char) !== false ||
strpos(strrev($alpha), $char) !== false)) {
$matches++;
}
if ($matches == $depth) return true;
}
return false;
}
http://codepad.org/sjzrVAAg
Ответ 9
Это также тривиально сделать с регулярным выражением:
preg_match('/ ((?=ab|bc|cd|de|ef|fg|gh).) {2,} /smix', "testabc")
Вам, очевидно, нужно заполнить список последовательных букв. И {2,}
просто считывает как минимум три буквы в диапазоне.
Ответ 10
Это мое мнение:
function checkConsecutiveness($string, $length = 3)
{
$tempCount = 1;
for($i = 0; $i < count($tokens = str_split(strtolower($string)) ); $i++)
{
// if current char is not alphabetic or different from the next one, reset counter
if(
ord($tokens[$i]) < 97 ||
ord($tokens[$i]) > 122 ||
ord($tokens[$i]) != (ord( $tokens[$i+1]) -1)
){
$tempCount = 1;
}
// else if we met given length, return true
else if(++$tempCount >= $length)
return true;
}
// no condition met by default
return false;
}
Он проверяет $string
на любую последовательность последовательных букв $length
.
checkConsecutiveness('[email protected]', 5) // returns true;
checkConsecutiveness('[email protected]', 5) // returns false;
Имейте в виду, что текущий символ находится в диапазоне 97-122, потому что галочка '[ ASCII # 96] и открытая фигурная скобка {[ASCII # 123] могут привести к ложному срабатыванию.
Ответ 11
Вы можете сделать это следующим образом (коды ASCII соответствуют алфавиту):
function check_str_for_sequences($str, $min = 3) {
$last_char_code = -1;
$total_correct = 0;
$str = strtolower($str);
for($i = 0; $i < strlen($str); $i++) {
//next letter in the alphabet from last char?
if(ord($str[$i]) == ($last_char_code + 1)) {
$total_correct++;
//min sequence reached?
if($total_correct >= ($min - 1)) {
return TRUE;
}
} else {
$total_correct = 0;
}
$last_char_code = ord($str[$i]);
}
return FALSE;
}
Использование:
$test = 'Lorem ipsum dolor abcsit amet';
echo '----->' . check_str_for_alpha($test); // ----->1
Ответ 12
Мои два цента:
function countOrderedCharacters($str, $count){
$matches = array();
preg_replace_callback('/(?=(\w{'.$count.'}))/',function($x) use(&$matches,$count) {
$seq = $x[1];
if($count === 1){
$matches[] = $seq;
return;
}
$dif = ord($seq[1]) - ord($seq[0]);
if (abs($dif)!=1) return;
for($i = 0 ; $i < strlen($seq)-1 ; $i++){
if(ord($seq[$i+1]) - ord($seq[$i]) != $dif) return;
}
$matches[] = $seq;
}, $str);
return $matches;
}
Ответ 13
Попробуйте эту функцию:
function checkForString($string,$l=4){
$length = strlen($string);
$result = 0;
for($i=0;$i<$length-1 && $result<4;$i++){
if($string[$i+1] == $string[$i]++) $result++;
}
if($result>=4) return true;
else return false;
}