【问题标题】:Matching A General Pattern In One String To Another将一个字符串中的通用模式与另一个字符串匹配
【发布时间】:2019-11-27 07:07:51
【问题描述】:

我有一个以这种格式存储在数组中的扑克手列表:

$hands = ['AsQdTc9h', 'AsQsTd9d' ...]

我还有一个 4 个字符的搜索字符串,使用字母 xyzw。例如,搜索字符串可能如下所示:

$searchString = 'xyxy';
$searchString = 'xyzw';
$searchString = 'yzyw';

搜索字符串的全部目的是为手中的小写字符识别所需的模式。

因此,如果 searchString 是 xyzw,这只是一种说“只选择没有小写字母相等的手”的方式。如果搜索字符串是xyxy,这就是说'只选择第一个和第三个小写字母相等且第二个和第四个小写字母相等的手。

换句话说,小写字母必须与搜索字符串的模式匹配。如何在 PHP 中实现这个?

【问题讨论】:

  • 也就是说AsQsTd9d中的小写字母是ssdd,而模式是xxyy
  • @Abolix 完全正确。我认为这是不言而喻的,但如果小写字母为ddhhsshhccdd 等,xxyy 也应该匹配。

标签: php


【解决方案1】:
$MyString = 'AsQdTc9h';
$MyString = preg_replace('/[^a-z]/', '', $MyString); // Get only the lowercase characters
// $MyString : sdch

$LetterArray = str_split($MyString);
$LetterArray = array_count_values($LetterArray);

$ReplaceList = ['x', 'y', 'z', 'w'];
$i = 0;
foreach ($LetterArray as $Letter => $result) {
    $MyString = str_replace($Letter, $ReplaceList[$i], $MyString);
    $i++;
}
echo $MyString; // expected output : xyzw

我想解释一下代码以便您理解它,首先我们使用正则表达式获取所有小写字符。然后我们将 4 个字符的单词变成一个数组,然后我们计算有多少个字符是相同的。

然后我们将结果替换为 xyzw 。

【讨论】:

    【解决方案2】:

    虽然这看起来像是一个模式匹配任务,但由于字符串的长度非常有限,伪暴力检查可能是最简单的。

    function pokerMatch(string $hand, string $pattern): bool
    {
        $hand = preg_replace('/[^a-z]/', '', $hand);
    
        for ($i = 0; $i < strlen($hand); $i++) {
            for ($j = $i+1; $j < strlen($hand); $j++) {
                if ($pattern[$i] === $pattern[$j] && $hand[$i] !== $hand[$j]) {
                    return false;
                }
                if ($pattern[$i] !== $pattern[$j] && $hand[$i] === $hand[$j]) {
                    return false;
                }
            }
        }
        return true;
    }
    

    这基本上是做什么的,它遍历模式字符串,获取每对字符并检查:

    • 如果模式位置 i 和 j 中的字母相等,则手串中的字符也必须相等;

    • 如果模式位置 i 和 j 中的字母不同,则手串中的字符也必须不同;

    如果其中任何一个不成立 - 模式不匹配

    如果在检查所有对后我们没有发现不匹配 - 那么它是匹配的。

    用法:

    var_dump(pokerMatch('AsQdTc9h', 'xyzw')); // => bool(true)
    var_dump(pokerMatch('AsQdTc9h', 'xyzz')); // => bool(false)
    var_dump(pokerMatch('AsQsTc9c', 'xxyy')); // => bool(true)
    var_dump(pokerMatch('AsQsTc9c', 'zzww')); // => bool(true) (it's agnostic to exact letters)
    

    【讨论】:

      【解决方案3】:

      您可以通过遍历每手牌和搜索字符串来解决此问题,记录哪个花色与哪个搜索字母匹配,并检查它们是否始终一致:

      $hands = ['AsQdTc9h', 'AsQsTd9d', 'AsKh9s9d'];
      $searchStrings = ['xyxy', 'xyzw', 'yzyw', 'ppqq'];
      
      function match_hand($hand, $search) {
          $h = preg_replace('/[^a-z]/', '', $hand);
          $matches = array();
          for ($i = 0; $i < strlen($search); $i++) {
              $s = $search[$i];
              // have we seen this search letter before? 
              if (isset($matches[$s])) {
                  // does it match the previous value? if not, it's an error
                  if ($matches[$s] != $h[$i]) return false;
              }
              else {
                  // haven't seen this search letter before, so this hand letter should not be in the matches array yet
                  if (in_array($h[$i], $matches)) return false;
              }
              $matches[$s] = $h[$i];
          }
          return true;
      }
      
      foreach ($hands as $hand) {
          foreach ($searchStrings as $search) {
              if (match_hand($hand, $search)) {
                  echo "hand $hand matches pattern $search\n";
              }
          }
      }
      

      输出:

      hand AsQdTc9h matches pattern xyzw
      hand AsQsTd9d matches pattern ppqq
      hand AsKh9s9d matches pattern yzyw
      

      Demo on 3v4l.org

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-16
        • 2019-01-12
        • 1970-01-01
        • 2012-03-21
        • 2021-08-17
        相关资源
        最近更新 更多