Двухсторонняя стеганография

19

Стеганография скрывает данное сообщение внутри данного носителя, создавая пакет, который не выглядит подозрительным. Для этой задачи вы напишите программу, которая принимает сообщение ASCII и носитель ASCII в качестве входных данных, а также возвращает или печатает пакет, идентичный носителю, за исключением того, что символы, соответствующие сообщению, удваиваются в том же порядке, в котором они отображаются в сообщение.

Правила:

  1. Если носитель уже содержит последовательности одного и того же символа более одного раза, и они не используются для кодирования символа сообщения, программа сократит их до одного символа.
  2. Если перевозчик не содержит символы сообщения в правильном порядке, программа может ничего не вернуть, сам перевозчик или ошибка.
  3. Вы можете предположить, что сообщение и носитель являются непустыми строками ASCII.
  4. Капитализация имеет значение: A не эквивалентно a.
  5. Если допустимо более одного пакета, ваша программа может вывести любой или все из них.
  6. Пробел - это персонаж, как любой другой персонаж.

Тестовые случаи:

Пакет Перевозчика Сообщений
"привет" "он прибыл?" "Он есть?" ИЛИ "Ариив?"
"сэр" "это прибыло?" "Пришел ли он?"
"foo" "он прибыл?" "ИЛИ" это прибыло? " ИЛИ ошибка.
«Машина» «Кошки классные». "CCaats arre col."
"машина" "Коты классные". "ИЛИ" Кошки классные. " ИЛИ ошибка.
"Кушетка" "Кушетка" "CCoouucchh"
"ооо" "ооооооооо" "оооо"
"о о" "оооооооо" "ооооо"

Это код гольф, поэтому побеждает меньше байтов.

jkpate
источник
5
Совсем не подозрительно ...: P
Quintec
Является ли "oooo oa"(с 2 пробелами) допустимым выводом для последнего контрольного примера?
Арно
3
Это недопустимый вывод, потому что порядок удвоенных символов в пакете должен соответствовать порядку символов в сообщении. В сообщении у нас есть 'o', затем '', затем 'o', но в вашем пакете есть пробел после o's
jkpate
Ах да, это имеет смысл.
Арно
1
Нет. Моя аргументация в пользу этого правила заключается в том, что вывод программы в случае отсутствия решения должен быть однозначным, поскольку решение невозможно. Три разрешенных выхода однозначны, но для дедуплицированного случая потребуется более тщательная проверка.
JKPATE

Ответы:

5

Желе , 28 байт

ẹⱮŒp<ƝẠ$ƇṪ
nƝ+çṬ¥a⁸ḟ0Ḥç¦ð¹ç?

Полная программа, принимающая carrierи в messageкачестве аргументов командной строки, которая печатает результат
(для неупаковываемых messageпечатает неизмененные carrier).

Попробуйте онлайн! Или посмотрите набор тестов .

Как?

ẹⱮŒp<ƝẠ$ƇṪ - Link 1, helper function to find the indices to double: carrier, message
           -                               e.g. "programming", "rom"
 Ɱ         - map across message with:
ẹ          -   indices of                       [[2,5], [3], [7,8]]
  Œp       - Cartesian product                  [[2,3,7],[2,3,8],[5,3,7],[5,3,8]]
        Ƈ  - filter keep if:
       $   -   last two links as a monad:
     Ɲ     -     for neighbours:
    <      -       less than?                    [1,1]   [1,1]   [0,1]   [0,1]
      Ạ    -     all truthy?                     1       1       0       0
           -                                    [[2,3,7],[2,3,8]]
         Ṫ - tail (if empty yields 0)                    [2,3,8]

nƝ+çṬ¥a⁸ḟ0Ḥç¦ð¹ç? - Main Link: carrier, message
                ? - if...
               ç  - ...condition: last Link (the helper function) as a dyad
             ð    - ...then: perform the dyadic chain to the left (described below)
              ¹   - ...else: do nothing (yields carrier)
                  - (the then clause:)
 Ɲ                - for neighbours in the carrier
n                 - not equal?
     ¥            - last two links as a dyad:
   ç              -   call last Link (the helper function) as a dyad
    Ṭ             -   untruth (e.g. [2,5] -> [0,1,0,0,1])
  +               - add (vectorises)
      a⁸          - logical AND with carrier
        ḟ0        - filter out zeros
            ¦     - sparse application...
           ç      - ...to indices: call last Link (the helper function) as a dyad
          Ḥ       - ...do: double (e.g. 'x' -> 'xx')
Джонатан Аллан
источник
3

JavaScript (ES6), 71 байт

Принимает вход как (message)(carrier).

s=>g=([c,...C],p)=>c?(c==s[0]?(s=s.slice(1),c)+c:p==c?'':c)+g(C,c):s&&X

Попробуйте онлайн!


Альтернативная версия, 66 байт

Если мы можем принять сообщение как массив символов:

s=>g=([c,...C],p)=>c?(c==s[0]?s.shift()+c:p==c?'':c)+g(C,c):s+s&&X

Попробуйте онлайн!


Редактировать : Спасибо @tsh за то, что заметил, что забыл удалить некоторый код при переходе с нерекурсивных на рекурсивные версии.

Arnauld
источник
Вы можете удалить, p=так как p передается параметром.
TSH
@tsh Упс. Это некоторый остаточный код из предыдущих нерекурсивных версий, который я забыл удалить. Спасибо!
Арнаулд
2

Haskell, 124 121 107 101 97 95 90 байт

(#).(++"ü")
"ü"#[]=[]
p@(m:n)#e@(c:d)|m/=c=c:p#snd(span(==c)d)|m==n!!0=m:m:n#d|1<2=m:n#e

Вызывает исключение «Неисчерпывающие шаблоны», если перевозчик не содержит сообщения.

Попробуйте онлайн!

Изменить: -5 байт благодаря @Laikoni.

Ними
источник
Я думаю, что переключение дел позволяет вам бросить m==c: попробуйте онлайн!
Лайкони
1

Сетчатка 0.8.2 , 67 байт

+`(.)(\1*)\1*(.*¶)(?(\1)(\1(\2)))(.*)$(?!¶)
$1$4$5¶$3$6
M!s`.*¶$
¶

Попробуйте онлайн! Принимает перевозчик в первой строке и сообщение во второй строке. Объяснение:

+`(.)(\1*)\1*(.*¶)(?(\1)(\1(\2)))(.*)$(?!¶)
$1$4$5¶$3$6

Процесс запускается из 1 или более одинаковых символов носителя. Если в сообщении также есть серия из 1 или более одинаковых символов, добавьте более короткий из двух циклов к выходу в двух экземплярах, в противном случае добавьте к выходу один символ носителя. Каждый запуск выходных символов заканчивается новой строкой, чтобы отличить ее от ввода. Знак « (?!¶)в конце» не позволяет регулярному выражению думать, что носитель является сообщением, когда сообщение исчерпано, как обычно $разрешено совпадать с тем, где ¶$будет совпадать.

M!s`.*¶$

Удалите все, если сообщение не было полностью закодировано.

Удалите новые строки из вывода.

Нил
источник
Я думаю, что он не проходит второй до последнего контрольного примера (который, честно говоря, у меня не было в первоначальном посте).
августа
@jkpate Спасибо за указание на это; Мне пришлось немного переписать свой подход.
Нил
0

Чисто , 118 байт

import StdEnv,StdLib
$[][]=[]
$[u:v]b#(_,w)=span((==)u)v
|b%(0,0)==[u]=[u,u: $if(v%(0,0)<>b%(1,1))w v(tl b)]=[u: $w b]

Попробуйте онлайн!

Сначала принимает перевозчик, затем сообщение.

Ошибки, Run time error, rule '$;2' in module 'main' does not matchесли сообщение не подходит.

Οurous
источник
0

Рубин , 73 байта

f=->m,c,b=p{x,*c=c;x ?(x==m[0]?x+m.shift: x==b ?'':x)+f[m,c,x]:m[0]?x:''}

Попробуйте онлайн!

Рекурсивная функция, принимает входные данные в виде массива символов.

На этот раз я надеялся использовать встроенный squeezeметод Ruby, который заключает подряд последовательные запуски одного и того же символа в один экземпляр. Но, к сожалению, нет - последние два тестовых случая все испортили так сильно, что мне пришлось прибегнуть к совершенно другому подходу, и это оказалось в основном портом ответа Арно .

Кирилл Л.
источник
0

Powershell, 134 байта

param($m,$c)$c-csplit"([$m])"|%{$i+=$o=$_-ceq$m[+$i]
if($o-or$_-cne"`0$h"[-1]){$h+=($_-replace'(.)(?=\1)')*($o+1)}}
$h*!($i-$m.Length)

Сценарий возвращает, empty stringесли перевозчик не содержит символы сообщения в правильном порядке.

Менее гольф тестовый скрипт:

$f = {

param($message,$carrier)
$carrier-csplit"([$message])"|%{                # split by chars of the message, chars itself included ([])
    $offset=$_-ceq$message[+$i]                 # 0 or 1 if current substring is a current message char (case-sensitive equality)
    $i+=$offset                                 # move to next message char if need it
    if($offset-or$_-cne"`0$h"[-1]){             # condition to remove redundant doubles after message char: arrrived -> arrived, ooo -> oo, etc
                                                # `0 to avoid exception error if $h is empty
        $h+=($_-replace'(.)(?=\1)')*($offset+1) # accumulate a double message char or a single substring without inner doubles: arried -> arived, anna -> ana, etc
    }
}
$h*!($i-$message.Length)                        # repeat 0 or 1 times to return '' if the carrier does not contain the message characters in the right order

}

@(
    ,('hi'         ,'has it arrived?'    ,'hhas iit arived?', 'hhas it ariived?')
    ,('hi?'        ,'has it arrived?'    ,'hhas iit arived??', 'hhas it ariived??')
    ,('sir'        ,'has it arrived?'    ,'hass iit arrived?')
    ,('foo'        ,'has it arrived?'    ,'')
    ,('Car'        ,'Cats are cool.'     ,'CCaats arre col.')
    ,('car'        ,'Cats are cool.'     ,'')
    ,('Couch'      ,'Couch'              ,'CCoouucchh')
    ,('oo'         ,'oooooooooo'         ,'oooo')
    ,('o o'        ,'oooo oooa'          ,'oo  ooa')
    ,('er'         ,'error'              ,'eerorr', 'eerror')
    ,('a+b'        ,'anna+bob'           ,'aana++bbob')
) | % {
    $message,$carrier,$expected = $_
    $result = &$f $message $carrier
    "$($result-in$expected): $result"
}

Выход:

True: hhas iit arived?
True: hhas iit arived??
True: hass iit arrived?
True:
True: CCaats arre col.
True:
True: CCoouucchh
True: oooo
True: oo  ooa
True: eerror
True: aana++bbob
Mazzy
источник
0

C (gcc) , 69 + 12 = 81 байт

g(char*m,char*_){for(;*_;++_)*m-*_?_[-1]-*_&&p*_):p p*m++));*m&&0/0;}

Компилировать с (12 байт)

-Dp=putchar(

Попробуйте онлайн!

g(char*m,char*_){
    for(;*_;++_)        //step through _
        *m-*_?          //check if character should be encoded
            _[-1]-*_&&  //no? skip duplicates
                p*_)    //    print non-duplicates
        :p p*m++));     //print encoded character twice
    *m&&0/0;            //if m is not fully encoded, exit via Floating point exception
}
attinat
источник