How to decrypt in php a string according to the specified rules?

To decrypt the cipher>11ге+20∆∆A+4µcњil->5•Ž®†G p+5f-7Ќf pro+10g+1悦ra->58->44m+1*m+2a喜er!

Rules of decoding the following:

- Start reading need with the leftmost character and move right.
- If you face any character except the special symbols, the symbol gets changes in the resulting line.
- Special notations are "->", "+", "-". After a special notation is always a number that is the argument.
- "->" — you need to go to the symbol with the number written in the argument (the count starts from 0).
- "+" — skip as many characters as written in the argument. The clock starts after the argument.
- "-" — is similar, but moves backwards (to the left)

The answer is the stitching.
April 7th 20 at 15:47
1 answer
April 7th 20 at 15:49
Solution
Something like this:
<?php declare(strict_types=1);

$input = '->11ге+20∆∆A+4µcњil->5•Ž®†G p+5f-7Ќf pro+10g+1悦ra->58->44m+1*m+2a喜er!';

class Decoder
{
 private $position = 0;
 private $output = ";

 private $state;

 private const STATE_FREE = 'processFree';
 private const STATE_MINUS = 'processMinus';
 private const STATE_READ_NUMBER = 'processReadNumber';

 private const METHOD_GO = 'goStack';
 private const METHOD_SKIP_RIGHT = 'skipStackRight';
 private const METHOD_SKIP_LEFT = 'skipStackLeft';

 private $stack;
 private $method;

 public function decode(string $input): string
{
 $this->position = 0;
 $this->output = ";
 $this->state = self::STATE_FREE;

 $length = mb_strlen($input, 'UTF-8');

 while ($this->position < $length){
 $symbol = mb_substr($input, $this->position, 1, 'UTF-8');
$this->{$this->state}($symbol);
}

 return $this->output;
}

 private function processFree(string $symbol): void
{
 switch ($symbol){
 case '-':
 $this->state = self::STATE_MINUS;
break;
 case '+':
 $this->method = self::METHOD_SKIP_RIGHT;
 $this->state = self::STATE_READ_NUMBER;
break;
default:
 $this->output .= $symbol;
break;
}

$this->position++;
}

 private function processMinus(string $symbol): void
{
 if($symbol === '>'){
 $this->method = self::METHOD_GO;
 $this->state = self::STATE_READ_NUMBER;
$this->position++;
return;
}

 $this->method = self::METHOD_SKIP_LEFT;
 $this->state = self::STATE_READ_NUMBER;
}

 private function processReadNumber(string $symbol): void
{
if($this->isNumber($symbol)){
 $this->stack .= $symbol;
$this->position++;
return;
}

 if($this->stack === null){
 throw new \InvalidArgumentException('Method has\'t number argument at position: '.$this->position);
}

$this->{$this->method}((int)$this->stack);
 $this->stack = null;
 $this->method = null;
 $this->state = self::STATE_FREE;

}

 private function isNumber(string $symbol): bool
{
 return !!preg_match('#[0-9]#',$symbol);
}

 private function goStack(int $arg): void
{
 $this->position = $arg;
}

 private function skipStackRight(int $arg): void
{
 $this->position += $arg;
}

 private function skipStackLeft(int $arg): void
{
 $this->position -= $arg;
}
}


$out = (new Decoder())->decode($input);
echo $out;

Actually, you have a set of rules and conditions. Start reading one character, and depending on current state generate the next step change the state, save the symbol and arrange the transition. Read about finite state machines.
!!preg_match - bud42 commented on April 7th 20 at 15:52
@lynn.Hagenes28, Yes, there is. But do not forget that this decision was made for a couple of minutes and the flight of thought is not always possible to catch. Scary in the moment there is nothing, on the efficiency of the code is not affected , of course, in this case, you could use ctype_digit. If you immediately yields code that does not need to refactor, I congratulate you. Although, you have those moments, example excerpts from your recent response:
function foo($args1, $args2) {
 $html = ";
 foreach ($args1 as $val) {
 $html .= $val;
}
 return $html;
}

echo foo($args1, $args2);


Correct would look like:
function foo(array $args) {
 return implode($args);
}

echo foo($args);


And even better:
function foo(string ... $args) {
 return implode($args);
}

echo foo(...$args);

So we will be able to directly control the type of the passed arguments. We are all not without sin. - Stone.Beat commented on April 7th 20 at 15:55
@charley_Roob42not, there just have a question to watch, because code like this. Of course not all at once running smoothly) - bud42 commented on April 7th 20 at 15:58
@lynn.Hagenes28,
I used it, however when calling $output[2], and so on returns a void, what's the problem?

preg_match("/->(\d+)/",$inputString,$output);

print($output[1]); - wilfred.Litt commented on April 7th 20 at 16:01
@Haleigh31may need to escape special characters, or to write down the regular season in single quotes, or use a function to escape regular expression
https://www.php.net/manual/ru/function.preg-quote.php
The ability to debug also need to download - bud42 commented on April 7th 20 at 16:04

Find more questions by tags PHP