douqiao1997 2016-08-06 17:54
浏览 46
已采纳

如何将非常相似的字符串中的方差输出到数组中?

I have something like this array of strings, as seen they are very similar, with the exception of the same one place in the string:

  $strings = [
        'This is +1% better than last time!',
        'This is +2% better than last time!',
        'This is +3% better than last time!',
        'This is +4% better than last time!',
        'This is +5% better than last time!',
        ...
    ];

  // Psuedo code

From this I'd like to end up with

$array = [
    '1',
    '2',
    '3',
    '4',
    '5',
    ...
];
// And preferrably
$string = 'This is +%s% better than last time!';

Via a function that takes any array of similar strings and outputs what is actually different in them.

  • 写回答

3条回答 默认 最新

  • duanjiati1755 2016-08-07 21:16
    关注

    Warning for a very long post with a lot of code!

    Thanks a lot for the help everybody, all of which gave me very good hints of where to go with this. Here is my solution / class to solve this problem, which is an extension of the code of Vicente Olivert Riera's answer and the method FlyingFoX explained in his/her answer:

    Link to GitHub repo

    class StringDiff
    
    {
        /**
         * The unformatted string to be used in the
         * vsprintf call
         * @var string
         */
        protected $unformattedString = '';
        /**
         * Array with arguments replacing the %s in the
         * unformatted string
         * @var array
         */
        protected $args = [];
        /**
         * Returns the arguments to be used for a vsprintf
         * call along with the format string
         * @return array
         */
        public function getArgs()
        {
            return $this->args;
        }
    
        /**
         * Returns the unformatted string to be used in
         * a vsprint call along with the arguments
         * @return string
         */
        public function getUnformattedString()
        {
            return $this->unformattedString;
        }
    
        /**
         * Takes an array argument of very similarly formatted
         * strings and fills in the $unformattedString and $args
         * variables from the data provided
         * @param  array  $strings Group of very similar strings
         * @return void
         */
        public function run(array $strings)
        {
    
            // If there are no strings, return nothing
    
            if (count($strings) == 0) return '';
    
            // Replacing % with %% so the vsprintf call doesn't
            // bug the arguments
    
            $strings = str_replace('%', '%%', $strings);
            $num_words = 0;
    
            // Explodes each string into many smaller containing
            // only words
    
            foreach($strings as $key => $string)
            {
                $strings[$key] = explode(' ', $string);
            }
    
            $num_words = count($strings[0]);
    
            // Array containing the indices of the substrings
            // that are different
    
            $sub_str_nr = [];
    
            // Loops through all the words in each string
    
            for ($n = 0; $n < $num_words; $n++)
            {
    
                // First round only sets the string to be compared with
    
                $first_round = true;
                for ($s = 0; $s < count($strings); $s++)
                {
                    if ($first_round)
                    {
                        $first_round = false;
                        $tmp[0] = $strings[$s][$n];
                    }
                    else
                    {
                        $tmp[1] = $strings[$s][$n];
                        if ($tmp[0] == $tmp[1])
                        {
                            $tmp[0] = $tmp[1];
                        }
                        else
                        {
                            if (!in_array($n, $sub_str_nr))
                            {
                                $sub_str_nr[] = $n;
                            }
                        }
                    }
                }
            }
    
            // Array to hold the arguments, i.e. all the strings
            // that differ from each other. From these the differences
            // will be deduced and put into the $this->args variable
    
            $args = [];
            foreach($sub_str_nr as $nr)
            {
                $tmpArgs = [];
                for ($a = 0; $a < count($strings); $a++)
                {
                    $tmpArgs[] = $strings[$a][$nr];
                }
    
                $args[] = $tmpArgs;
            }
    
            foreach($args as $key => $arg)
            {
    
                // Offset from the beginning of the string that is still the same
    
                $front_offset = 0;
    
                // If the offset from the beginning has been maxed
    
                $front_flag = true;
    
                // Offset from the end of the string that is still the same
    
                $back_offset = 0;
    
                // Id the offset from the end has been maxed
    
                $back_flag = true;
    
                // The string to be compared against is the first in line
    
                $tmp = $arg[0];
                while ($front_flag || $back_flag)
                {
    
                    // Flag 1 & 2 limits to only one increase of offset per loop
    
                    $flag1 = true;
                    $flag2 = true;
                    for ($a = 1; $a < count($strings); $a++)
                    {
    
                        // The two following if statements compare substring
                        // to substring of length one
    
                        if ($front_flag && $flag1)
                        {
                            if (substr($tmp, $front_offset, 1) != substr($arg[$a], $front_offset, 1) || is_numeric(substr($arg[$a], $front_offset, 1)))
                            {
                                $front_flag = false;
                            }
                            else
                            {
                                $front_offset++;
                                $flag1 = false;
                            }
                        }
    
                        if ($back_flag && $flag2)
                        {
                            if (substr($tmp, strlen($tmp) - $back_offset - 1, 1) != substr($arg[$a], strlen($arg[$a]) - $back_offset - 1, 1) || is_numeric(substr($arg[$a], strlen($arg[$a]) - $back_offset - 1, 1)))
                            {
                                $back_flag = false;
                            }
                            else
                            {
                                $back_offset++;
                                $flag2 = false;
                            }
                        }
                    }
                }
    
                // Sets the $this->args variable with the found arguments
    
                foreach($arg as $arkey => $ar)
                {
                    $this->args[$arkey][$key] = (float)substr($arg[$arkey], $front_offset, strlen($arg[$arkey]) - $back_offset - $front_offset);
                }
    
                // Changes the strings for the unformatted string, switches
                // out the varying part to %s
    
                $strings[0][$sub_str_nr[$key]] = substr($arg[0], 0, $front_offset) . '%s' . substr($arg[0], strlen($arg[0]) - $back_offset, $back_offset);
            }
    
            // Creates the unformatted string from the array of
            // words, which originates from the original long string
    
            $unformattedString = '';
            foreach($strings[0] as $string)
            {
                $unformattedString.= ' ' . $string;
            }
    
            // Trim whitespaces in the beginning and end of the
            // formatted string
    
            $this->unformattedString = trim($unformattedString);
            return;
        }
    }
    

    How to use:

    $stringd = new StringDiff;
    
    $test_array = [
      "Your Cooldown Reduction cap is increased to 41% and you gain 1% Cooldown Reduction",
      "Your Cooldown Reduction cap is increased to 42% and you gain 2% Cooldown Reduction",
      "Your Cooldown Reduction cap is increased to 43% and you gain 3% Cooldown Reduction",
      "Your Cooldown Reduction cap is increased to 44% and you gain 4% Cooldown Reduction",
      "Your Cooldown Reduction cap is increased to 45% and you gain 5% Cooldown Reduction",
    ];
    
    $stringd->run($test_array);
    foreach($stringd->getArgs() as $arg)
    {
      echo vsprintf($stringd->getUnformattedString(), $arg) . '<br>';
    }
    

    Outputs:

    Your Cooldown Reduction cap is increased to 41% and you gain 1% Cooldown Reduction
    Your Cooldown Reduction cap is increased to 42% and you gain 2% Cooldown Reduction
    Your Cooldown Reduction cap is increased to 43% and you gain 3% Cooldown Reduction
    Your Cooldown Reduction cap is increased to 44% and you gain 4% Cooldown Reduction
    Your Cooldown Reduction cap is increased to 45% and you gain 5% Cooldown Reduction
    array(5) {
      [0]=>
      array(2) {
        [0]=>
        float(41)
        [1]=>
        float(1)
      }
      [1]=>
      array(2) {
        [0]=>
        float(42)
        [1]=>
        float(2)
      }
      [2]=>
      array(2) {
        [0]=>
        float(43)
        [1]=>
        float(3)
      }
      [3]=>
      array(2) {
        [0]=>
        float(44)
        [1]=>
        float(4)
      }
      [4]=>
      array(2) {
        [0]=>
        float(45)
        [1]=>
        float(5)
      }
    }
    Your Cooldown Reduction cap is increased to %s%% and you gain %s%% Cooldown Reduction
    

    And yes, if you are wondering, this is related to the Riot API.

    If you have suggestions for improvement or any changes at all, feel free to comment down below :)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 Mac系统vs code使用phpstudy如何配置debug来调试php
  • ¥15 目前主流的音乐软件,像网易云音乐,QQ音乐他们的前端和后台部分是用的什么技术实现的?求解!
  • ¥60 pb数据库修改与连接
  • ¥15 spss统计中二分类变量和有序变量的相关性分析可以用kendall相关分析吗?
  • ¥15 拟通过pc下指令到安卓系统,如果追求响应速度,尽可能无延迟,是不是用安卓模拟器会优于实体的安卓手机?如果是,可以快多少毫秒?
  • ¥20 神经网络Sequential name=sequential, built=False
  • ¥16 Qphython 用xlrd读取excel报错
  • ¥15 单片机学习顺序问题!!
  • ¥15 ikuai客户端多拨vpn,重启总是有个别重拨不上
  • ¥20 关于#anlogic#sdram#的问题,如何解决?(关键词-performance)