LINUX.ORG.RU

Выделение подстроки, из которой состоит строка

 ,


0

1

Привет всем. В общем есть одна задачка, связанная с шифрованием/дешифрованием (учебная), там с помощью сравнения открытого и закрытого текста (тритемиус) нахожу строку с ключом.

Выглядит строка с ключом примерно так:

СтулСтулСтулСтулСтулСтулСт
ТабуретТабуретТабуретТабуретТабур

Было бы здорово, если бы на автомате из этой строки выделить слово, из которого она составляется, может кто знает алгоритм, или готовую реализацию?

Желательно C/C++

★★★★★

Если она выглядит, как показано - что мешает пробежать от начала до первой заглавной буквы?

deadline
()

Вначале кандидат в первом случае «C», следующий отрезок длины(«С») не совпадает с «C», увеличиваем кандидата до тех пор, пока он не совпадёт.

aptyp ★★★★
()
Ответ на: комментарий от false

Тогда можно посмотреть в сторону суфиксных деревьев

deadline
()
Ответ на: комментарий от false

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

minakov ★★★★★
()

Предлагаю такой алгоритм:

Начинаешь брать с конца последовательности по одному символу и сравнивать полученную последовательность с началом исходной.

ТабуретТабуретТабуретТабуретТабу -> р
ТабуретТабуретТабуретТабуретТаб  -> ур
ТабуретТабуретТабуретТабуретТа   -> бур
ТабуретТабуретТабуретТабуретТ    -> абур
ТабуретТабуретТабуретТабурет     -> Табур

Так ты найдешь наибольшую повторяющуюся последовательность (строка слева). Затем применяешь к ней этот же алгоритм рекурсивно пока не сможешь выделить никакую последовательность. Оставшаяся строка будет наименьшей повторяющейся последовательностью.

Как-то так.

no-such-file ★★★★★
()
Ответ на: комментарий от aptyp
AbAbAbAbAbAbAbAbAbAbAbAbCdAbA -> b
AbAbAbAbAbAbAbAbAbAbAbAbCdAb -> Ab // совпадение, начинаем сначала

AbAbAbAbAbAbAbAbAbAbAbAbCdA -> b
AbAbAbAbAbAbAbAbAbAbAbAbCd -> Ab // совпадение, начинаем сначала

AbAbAbAbAbAbAbAbAbAbAbAbC -> d
AbAbAbAbAbAbAbAbAbAbAbAb -> Cd
AbAbAbAbAbAbAbAbAbAbAbA -> bCd
AbAbAbAbAbAbAbAbAbAbAb -> AbCd
...
A -> bAbAbAbAbAbAbAbAbAbAbAbCd
ничего -> AbAbAbAbAbAbAbAbAbAbAbAbCd // больше ничего - это последовательность

Итого, последовательность : AbAbAbAbAbAbAbAbAbAbAbAbCd

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)

Лови
// gcc main.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char str[]=«BlaBlyaBlaBlyaBlaBlyaBlaBlyaBla»;
char key[128];

int n=1;

GetKey()
{
char * pos=strstr(&str[n],key);
if(pos>0)
{
if(strlen(key)==(pos-str))
{
printf(«Find period %d, key %s\n»,strlen(key),key);
} else
{
strncpy(key,str,pos-str);
GetKey();
}

} else

printf(«ERROR NOT FIND %s\n»,key);
}

void main(void)
{
key[n-1]=str[n-1];
key[n]=0;
GetKey();
}

ilovewindows ★★★★★
()

Алгоритмическая задача здесь элементарная. Если вы планировали стать программистом, советую пересмотреть ваши планы на будущую профессию.

trex6 ★★★★★
()
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

bool isKey(char *str, int len, int keylen)
{
    for(int i = 0; i < keylen; i++) {
        char curchar = str[i];
        for (int j = i + keylen; j < len; j+= keylen) {
            if (curchar != str[j]) return false;
        }
    }
    return true;
}

int main()
{
    char *s="ТабуретТабуретТабуретТабуретТабур";
    int len = strlen(s);
    for(int i = 1; i < len/2; i++) {
        if(isKey(s,len,i)) {
            printf("%i\n",i);
            exit(EXIT_SUCCESS);
        }
    }
    exit(EXIT_FAILURE);
}
at ★★
()
Ответ на: комментарий от no-such-file

Нифика, это тред-детектор систематизаторов тредов

ilovewindows ★★★★★
()
Ответ на: комментарий от no-such-file

Все верно. Печатается количество байт в ключе. Ограничений на набор символов не вижу. Возможно в качестве ключа используются японские иероглифы.

at ★★
()
Ответ на: комментарий от false

Да что тут придумывать? Есть алгоритм быстрого поиска подстроки в строке, на его основе _очень_ быстро получается решение вашей задачи. Что тут еще думать?

trex6 ★★★★★
()
Ответ на: комментарий от trex6

Ну раз Вам это ясно и понятно, предлагаю Вам удалиться из моего треда подальше и наблюдать из своей берлоги. Премного благодарен, спасибо за помощь.

false ★★★★★
() автор топика
Ответ на: комментарий от trex6

Точно, как говаривают программеры на дельфях пойду искать компонент рисующий тигрёнка.

ilovewindows ★★★★★
()

Пользуясь тегом Qt предлагаю вам такое:

#include <QCoreApplication>
#include <iostream>

const QString orig="AbcAbcCdeAbcAbcCdeFghAbcAbcCdeAbcAbcCdeFghAbcAbcC";

bool notCycle(const QList<QChar> &arg1, const QList<QChar> &arg2) {
    bool cycle=false;
    for(int i=0; i!=arg1.size() && i!=arg2.size(); ++i)
        if (arg1.at(i)!=arg2.at(i)) cycle=true;
    return cycle;
}

QList<QChar> mostLongCycle(QList<QChar> &arg) {
    QList<QChar> back;
    QList<QChar> orig=arg;

    do {
        if (arg.size()>0) back.push_front(arg.takeLast());
        else return back;
    } while (notCycle(orig, back));

    return back;
}


QList<QChar> fillList(const QString& str) {
    QList<QChar> res;
    for(int i=0; i!=str.size(); ++i)
        res.push_back(str.at(i));
    return res;
}

int main(int argc, char *argv[])
{
    QList<QChar> key;
    QList<QChar> prev;
    QList<QChar> str=fillList(orig);
    if (argc>1) str=fillList(QString(argv[1]));

    do {
        prev=key;
        key=mostLongCycle(str);
    } while (str.size()>0);

    // Против циклических ключей
    if (!notCycle(key, prev) && key.size()!=prev.size()) key+=prev;

    for(int i=0; i!=key.size(); ++i) std::cout << key.at(i).toAscii();
    std::cout << std::endl;
}
no-such-file ★★★★★
()

Автокорреляционную функцию посчитай

Gvidon ★★★★
()
Ответ на: комментарий от at

От оно че... Тем не менее, у вас ключ должен быть не меньше половины строки. А если ключ длиннее? AbcAbcCdeAbcAbcCdeFghAbcAbcCde и ключ не найден.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Чуток исправил

int main(int argc, char *argv[])
{
    QList<QChar> key;
    QList<QChar> prev;
    QList<QChar> str=fillList(orig);
    if (argc>1) str=fillList(QString(argv[1]));

    int round=0;
    do {
        prev=key;
        key=mostLongCycle(str);
        ++round;
    } while (str.size()>0);

    // Против циклических и вида 'ротор'
    if ( round>2 && !notCycle(key, prev) && key.size()!=prev.size())  key+=prev;

    for(int i=0; i!=key.size(); ++i) std::cout << key.at(i).toAscii();
    std::cout << std::endl;
}
no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

А почему тогда ключиком не считать «BlaBlyaBlaBlyaBlaBlyaChortBlaBlyaBla» целиком ? Остальное не убралось. Откуда такая уверенность что именно «BlaBlyaBlaBlyaBlaBlyaChort» ?

зы. Это шифрование Цезарь использовал вообще с одной буквой, потом монахи. Были любители среди них себя поистязать, но не до такой же степени. И ключ они запиской открытым текстом передавали или устно. С трудом представляю как можно ключ «дятелдятелдят» сообщить клиенту. Выбраковывать надо такие ключи при вводе как ошибочные и не париться.

ilovewindows ★★★★★
()
Ответ на: комментарий от ilovewindows

А почему тогда ключиком не считать «BlaBlyaBlaBlyaBlaBlyaChortBlaBlyaBla» целиком ?

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

no-such-file ★★★★★
()
Ответ на: комментарий от ilovewindows

С трудом представляю как можно ключ «дятелдятелдят» сообщить клиенту. Выбраковывать надо такие ключи при вводе как ошибочные и не париться.

У ТС обратная задача, он имея открытый и закрытый текст находит текст с циклически повторяющимся ключём. Нужно выделить из текста наименьшую циклическую часть (т.е. ключь как он был задан при зашифровке).

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Для определения ключа он должен полностью повторятся как минимум два раза. Т.е. в последовательности «12312» ключом может быть как «123» так и «12312», зависит от последующих символов.

У меня стоит условие как минимум два повторения + хотя бы один символ. Возможно достаточно проверять только 2 повторения, т.е. «for(int i = 1; i <= len/2; i++)» в main. Зависит от задачи.

at ★★
()
Ответ на: комментарий от at

Для определения ключа он должен полностью повторятся как минимум два раза

Кто сказал? Ключ может вообще не повторяться.

no-such-file ★★★★★
()

После небольших раздумий ко мне пришёл в голову подобный алгоритм: http://rghost.ru/42914369

bool Subkey::checkKey(int keyStart) const {
    QString key1 = key.left(keyStart);
    QString key2 = key.right(key.length() - keyStart);
    bool result = false;

    if (key2.startsWith(key1) || key1.startsWith(key2)) {
        // try to tile keystring with found key1
        QString keySnapshot;
        while (keySnapshot.length() < key.length()) {
            keySnapshot += key1;
        }
        result = keySnapshot.startsWith(key);
    }

    return result;
}


void Subkey::output() {
    int keyEnd = -1;

    for (int i = 1; i < key.length(); i++) {
        if (key[0] == key[i] && checkKey(i)) {
            keyEnd = i;
            break;
        }
    }

    if (keyEnd != -1) {
        QString keyword = key.left(keyEnd);
        std::cout << "Key is: " << keyword.toStdString() << std::endl;
    } else {
        std::cout << "Key was not found in: " << key.toStdString() << std::endl;
    }
}
KennyMinigun ★★★★★
()
Ответ на: комментарий от no-such-file

Неисповедимы пути ТСа, ориентируюсь на это
http://school-555.narod.ru/kript/5.htm там речь про слова.
Само слово при известном полностью ключе представляет собой чисто игровой интерес, расшифровать и показать.

зы. Вот в ключе олололололололо ,кстати, какое ключевое слово ?

ilovewindows ★★★★★
()
Ответ на: комментарий от no-such-file

Хотел поизобретать велосипедов, но понял, что, в общем, буду заниматься тем же, что и no-such-file

elfy
()

Что мешает тупо в лоб решить задачу?

#!/usr/bin/python3

def check_tiling(tile, s):
	repetitions = len(s) // len(tile)
	appendix_len = len(s) % len(tile)
	return s == tile * repetitions + tile[:appendix_len]

def get_min_tile(s):
	for i in range(1, len(s)):
		tile = s[:i]
		if check_tiling(tile, s):
			return tile
	return s

print(get_min_tile('СтулСтулСтулСтулСтулСтулСт'))
kvap
()
Ответ на: комментарий от ilovewindows

Вот в ключе олололололололо ,кстати, какое ключевое слово ?

Если я правильно понял ТСа, то «ол»... Логично же выбрать наименьший ключ...

solovey ★★
()
Ответ на: комментарий от solovey

Ага, именно такой. В общем задача решена, алгоритм на моём наборе данных работает, а на остальных вообще пофигу.

false ★★★★★
() автор топика

pls see gasfild string for more

у тя задача факторизации строки с возможным остатком(префиксом ключа)

лобовое решение квадратично(линейное удлинение пробы начиная с 1 символа и вплоть до всей строки*проверка )

решение используещее суффиксное дерово - nlogn?

если учесть что ключ есть всегда ....

qulinxao ★★☆
()
Ответ на: комментарий от solovey

Это я к тому, что в общем случае понять какой период на таких данных нельзя, от «oл» до «олололололололо» . Идея то сначала была здравая, писать с большой буквы начало ключевого слова и первый исходник из 5 строк эту задачу решал. Можно конечно еще 5 дописать и будет работать и с повторяющимися подстроками внутри ключа. Но конечно классы,шаблоны, qt и проч. на такую задачку это пять, это впечатляет. Зря ржут на дельфистами-видузятниками, когда они чтобы линию нарисовать гуглят компонент «рисовальщик линий», ой зря.

ilovewindows ★★★★★
()

Посчитай префикс-функцию для строки (та, что в алгоритме Кнута-Морриса-Пратта юзается). Её значение на последнем символе будет меньше длины строки как раз на длину повторяющейся последовательности.

Работает за O(длина строки).

anonymous
()
Ответ на: комментарий от false

да забей ты на этого trex6 - судя по его комментам, это вообще тролль какой-то.

anonymous
()
Ответ на: комментарий от ilovewindows

Но конечно классы,шаблоны, qt и проч. на такую задачку это пять, это впечатляет. Зря ржут на дельфистами-видузятниками, когда они чтобы линию нарисовать гуглят компонент «рисовальщик линий», ой зря.

Конечно зря. А вот за ваше char key[128] я бы сразу расстреливал.

no-such-file ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.