@legatobrown

Как расшифровать в php строчку по указанным правилам?

Расшифровать шифр ->11гe+20∆∆A+4µcњil->5•Ћ®†Ѓ p+5f-7Ќ¬f pro+10g+1悦ra->58->44m+1*m+2a喜er!

Правила его расшифровки следующие:

- Начинать чтение нужно с крайнего левого символа и двигаться вправо.
- Если вы сталкиваетесь с любым символом, кроме специальных обозначений, то данный символ без изменений попадает в результирующую строчку.
- Специальными обозначениями являются "->", "+", "-". После специального обозначения всегда идет число, являющееся аргументом.
- "->" — вам необходимо перейти к символу с номером, записанном в аргументе (счет начинается с 0).
- "+" — пропустить столько символов, сколько записано в аргументе. Отсчет начинается после аргумента.
- "-" — аналогично, но перемещение происходит назад (влево)

Ответом является строчка.
  • Вопрос задан
  • 479 просмотров
Решения вопроса 1
@Uinit
Как-то так:
<?php declare(strict_types=1);

$input = '->11гe+20∆∆A+4µcњil->5•Ћ®†Ѓ 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;

Собственно, у вас есть набор правил и состояний. Начинаете считывать по одному символу и в зависимости от текущего состояния производите дальнейшие действия - меняете состояние, сохраняете символ, организуете переход. Почитайте про конечные автоматы.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы