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

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

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

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
ИТЦ Аусферр Магнитогорск
от 100 000 до 160 000 ₽