21

これはとても明白に思えますが、私はこれを行う方法を見つけることができません。
これを行うための通常のPHP関数もあると思いますが、それでも1.5時間の集中的なGoogle検索の後で十分に隠されたままです。

欲しいもの

  • 文字列を入力として受け取る関数。
  • その文字列が3文字を超えるアルファベット順のシーケンスを持っている回数をチェックします。
  • 3を超えるシーケンスが見つかった場合はtrueを返します。

"youlookgreatbcdetoday" =>には"bcde"が含まれています...したがってtrueを返す必要があります
"youlookgreatklmtoday" =>には"klm"のみが含まれています...したがってfalseを返す必要があります
"youlookgreattoday" =>アルファベット順に並べられたシーケンスはありませんその中で、falseを返します


考えられるユースケース

  • パスワード強度チェッカー
  • 言葉遊び
  • ..。

免責事項:私はあなたに見せるためのコードがすでにあるといいのですが、文字通りまだ何もありません。
私が思いついたのは、文字列を配列に分割し、配列に魔法をかけることだけでした...しかし、それでも私は行き詰まりました。

あなたの一人が私を救ってくれることを願っています:)

4

13 に答える 13

17

それでは、ループとカウンター(増加のみ)を使用した簡単な実装から始めましょう。

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番号)が前の文字より1つ多いかどうかをチェックします。その場合、カウントパラメータが増加します。それ以外の場合は、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);
}
于 2012-08-25T19:16:12.830 に答える
4

ループが少なく、条件があれば!

  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;
  }
于 2012-08-25T20:09:27.283 に答える
4
<?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"
于 2012-08-25T19:24:11.827 に答える
2

これは私が思いついたものです:

/**
 * @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's 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's 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));

私が投げた文字列に取り組みました。また、カウントしたい文字数を選択することもできます。やった!

于 2012-08-25T19:38:29.380 に答える
1

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;
}

この関数が行うことは、文字列を文字ごとに繰り返すことです。現在の文字のASCII値を取得し、それを前ord()の文字のASCII値と比較するために使用します。それらが順方向または逆方向のいずれかに順番に並んでいる場合は、カウンターをインクリメントします。カウンターがヒットすると、!を返します。4true

これは順方向と逆方向のシーケンスに一致し、大文字と小文字を区別しません。だから、他の何よりも、abcd一致し、aBcD意志、そしてまた!DcBa

于 2012-08-25T19:15:07.410 に答える
1

これが私が思いついた簡単な解決策です:

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";

出力はSTRGOODおよびSTR3GOODです。 $minMatchLength関数がtrueを返すために必要な行の文字数です。("testing"には"st"がありますが、長さは3なので、falseを返します。

編集 私はそれを更新して、「AbCdE」もチェックしました。これだけordでは機能しません。

于 2012-08-25T19:16:11.680 に答える
1

文字の不等式比較では、暗黙的にord()値が使用されます。微調整できる簡単なスクリプトを次に示します(特に大文字と小文字を区別しない場合)。

<?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";
于 2012-08-25T19:24:03.793 に答える
1

多分単純化?大文字と小文字を区別しない場合は、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

于 2012-08-25T19:27:14.013 に答える
1

正規表現を使用するのも簡単です。

preg_match('/  ((?=ab|bc|cd|de|ef|fg|gh).)  {2,}  /smix', "testabc")

明らかに、連続する文字のリストを完成させる必要があります。そして{2,}、範囲内の最低3文字をプローブするだけです。

于 2012-08-25T19:32:49.003 に答える
1

これは私の見解です:

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('1@abcde1', 5) // returns true;
checkConsecutiveness('1@abcd1', 5) // returns false;

ティック`[ ASCII#96]と開いた中括弧{[ASCII#123]は誤検知につながる可能性があるため、現在の文字が97〜122の範囲にあることを確認してください。

于 2012-08-25T19:51:29.433 に答える
0

このように行うことができます(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
于 2012-08-25T19:28:35.840 に答える
0

私の2セント:

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;
}
于 2012-08-26T06:20:35.590 に答える
-1

この関数を試してください:

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;
}
于 2012-08-25T19:15:41.760 に答える