1

Тема: Кодування та декодування даних. з Java в c++

Доброго дня. суть задачі: Створити систему кодування текстових данних, в якій кожен символ кодується комбінацією чотирьох символів. кодуючий символ може приймати одне із чотирьох значень, при цьому, типи закодованого символів (спецсимволи, великі чи малі літери, інше) задається першим кодуючим символом
Щоб не вигадувати велосипед, за основу взяла генетичнийц код : A, G, C, T - кодуючі символи.
Створила чотиривимірний масив, та вівдповідні методи. програму написала мовою Java, але викладач сказав, що необхідно переписати на C++, з яким я не надто товаришую. викладаю код мовою Java. можливо хтось знає, як його реалізувати на C++? Дякую.

import java.util.Scanner;

/**
 * @author D_Sky
 * Перший нуклеотид - вказує на регістр в таблиці
 * А - спецсимволи
 * G - малі літери
 * C - великі літери
 * T - додатково
 */
class H1 {
    static char[][][][] symbol = new char[][][][]
    {
        //A
        {
            //A
            {
                //A
                {
                    //A,G,C,T
                    ' ', '\n', '\t', '`'
                },
                //для економії місця увесь масив не викладую.
    };
    static String code = "";

    /**
     *  
     * @param args 
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();//отримуэмо вхідну строку
        char[] c = s.toCharArray();//отримуємо масив чарів
        //кодуємо отриману строку
        for(int i = 0; i < c.length; i++){
            code = code + codengChar(c[i]);
        }
        System.out.println(code);
        //декодуэмо строку
        System.out.println(decoding());
    }

    private static String codengChar(char c) {
        String s = "";
        boolean is = false;
        for(int i = 0; i < 4; i++){
            for(int a = 0; a < 4; a++){
                for(int b = 0; b < 4; b++){
                    for(int d = 0; d < 4; d++){
                        if((int)c == (int)symbol[i][a][b][d]){
                            s += getDNACode(i);
                            is = true;
                            break;
                        }
                    }
                    if(is){break;}
                }
                if(is){break;}
            }
            if(is){break;}
        }
        return s;
    }

    private static String getDNACode(int i){
        switch(i){
            case 0 : return "A";
            case 1 : return "G";
            case 2 : return "C";
            case 3 : return "T";
            default : return "";
        }
    }

    private static String decoding() {
        String s = "";
        String[] segment = cut(4);
        for(int i = 0; i < segment.length; i++){
            char[] c = segment[i].toCharArray();
            s += symbol[getIntValue(c[0])][getIntValue(c[1])][getIntValue(c[2])][getIntValue(c[3])];
        }
        return s;
    }

    private static String[] cut(int a) {
        String[] s = new String[code.length() / a];
        int ind = 0;
        for(int i = 0; i < code.length(); i += a){
            s[ind] = i + a < code.length() ? code.substring(i, i + a) : code.substring(i);
        }
        return s;
    }

    private static int getIntValue(char c) {
        int i = -1;
        if(c == 'A'){
            i = 0;
        }else if(c == 'G'){
            i = 1;
        }else if(c == 'C'){
            i = 2;
        }else if(c == 'T'){
            i = 3;
        }
        return i;
    }

}

2

Re: Кодування та декодування даних. з Java в c++

Вибачте, прогавилаЖ :

if((int)c == (int)symbol[i][a][b][d]) {
    s += getDNACode(i);
    is = true;
    break;
}

має бути

if((int)c == (int)symbol[i][a][b][d]) {
    s += getDNACode(i);
    s += getDNACode(a);
    s += getDNACode(b);
    s += getDNACode(d);
    is = true;
    break;
}

3

Re: Кодування та декодування даних. з Java в c++

DianaSky написав:

.. при цьому, типи закодованого символів (спецсимволи, великі чи малі літери, інше) задається першим кодуючим символом

Не зрозумів.

DianaSky написав:

Створила чотиривимірний масив, ..

    static char[][][][] symbol = new char[][][][]

Не бачу причин користувати такі конструкції для цієї задачі.

DianaSky написав:

суть задачі: Створити систему кодування текстових данних, в якій кожен символ кодується комбінацією чотирьох символів. кодуючий символ може приймати одне із чотирьох значень, ..
Щоб не вигадувати велосипед, за основу взяла генетичнийц код : A, G, C, T - кодуючі символи.

Це візьмемо за основу і будемо рішати початкову задачу.

// nucleobase.hpp

#ifndef NUCLEOBASE_HPP
#define NUCLEOBASE_HPP

#include <cstdint>

#define B nucleobase_t

enum struct B : uint8_t {
    A = 0,
    C = 1,
    G = 2,
    T = 3,
};
char to_char(B const n) {
    return "ACGT"[(uint8_t)n & 3];
}
B from_char(char const c) {
    switch(c) {
        case 'A': case 'a': return B::A;
        case 'C': case 'c': return B::C;
        case 'G': case 'g': return B::G;
        case 'T': case 't': return B::T;
        default: throw "Unexpected symbol occurred.";
    }
}

#undef B // nucleobase_t

#endif // NUCLEOBASE_HPP

// https://en.cppreference.com/w/cpp/language/enum

Кожний екземпляр потребує по 2 біти. Можемо їх обєднати по 4 щоб зібрати байт.
І візьмемо union щоб переганяти кожний char в 4 елементи:

// nucleos_union.hpp

#ifndef NUCLEOS_UNION_HPP
#define NUCLEOS_UNION_HPP

#include <string>
#include "nucleobase.hpp"

#define C char
#define B nucleobase_t
#define U nucleos_union_t

union U {
    C ch;
    struct N {
        B n0 : 2, n1 : 2, n2 : 2, n3 : 2;
        N() { }
        N(B n0, B n1, B n2, B n3) : n0(n0), n1(n1), n2(n2), n3(n3) { }
        N(C n0, C n1, C n2, C n3)
            : n0(from_char(n0))
            , n1(from_char(n1))
            , n2(from_char(n2))
            , n3(from_char(n3))
        { }
    } nucleos;
    U() { }
    U(C const &c) : ch(c) { }
    U(B n0, B n1, B n2, B n3) : nucleos(n0, n1, n2, n3) { }
    U(C n0, C n1, C n2, C n3) : nucleos(n0, n1, n2, n3) { }
    U(C const *s) : nucleos(s[0], s[1], s[2], s[3]) { }
};

void encode(C const *src, C *dest, int src_len) {
    for(int i = 0; i < src_len; ++i) {
        U v = src[i];
        *dest++ = to_char(v.nucleos.n0);
        *dest++ = to_char(v.nucleos.n1);
        *dest++ = to_char(v.nucleos.n2);
        *dest++ = to_char(v.nucleos.n3);
    }
}
void decode(C const *src, C *dest, int dest_len) {
    for(int i = 0; i < dest_len; ++i) {
        dest[i] = U(src).ch;
        src += 4;
    }
}

#define S std::string
S encode(S const &src) {
    size_t src_len = src.length();
    S dest(src_len << 2, '\0');
    encode(src.c_str(), const_cast<C *>(dest.c_str()), src_len);
    return dest;
}
S decode(S const &src) {
    size_t dest_len = src.length() >> 2;
    S dest(dest_len, '\0');
    decode(src.c_str(), const_cast<C *>(dest.c_str()), dest_len);
    return dest;
}
#undef S // std::string

#undef U // nucleos_union_t
#undef B // nucleobase_t
#undef C // char

#endif // NUCLEOS_UNION_HPP

// https://en.cppreference.com/w/cpp/language/union
// https://en.cppreference.com/w/cpp/language/memory_model

Але тіла функцій краще перенести в відповідні *.cpp.

І в main просто викликаємо encode, decode.

// main.cpp

#include <iostream>
#include <string>
#include "nucleobase.hpp"
#include "nucleos_union.hpp"

#define U nucleos_union_t

#define A nucleobase_t::A
#define C nucleobase_t::C
#define G nucleobase_t::G
#define T nucleobase_t::T

int main(int argc, char *argv[]) {
    std::string s;
    std::cin >> s;
    std::cout << s << "\r\n";
    s = encode(s);
    std::cout << s << "\r\n";
    s = decode(s);
    std::cout << s << "\r\n";
    return 0;
}
/*//
void test_syntax() {
    U u0 = '\0';       // ok
    U u1 = { '\0' };   // ok
    U u3 = { A, C, G, T };         // ok
    U u4 = { 'A', 'C', 'G', 'T' }; // ok
    U u5 = { "ACGT" }; // ok
    U u6 = "ACGT";     // ok
    U u7(A, A, A, A);  // ok
    u7.ch = '1';                   // ok
    u7.nucleos = { A, C, G, T };   // ok
}
//*/

#undef A // nucleobase_t::A
#undef C // nucleobase_t::C
#undef G // nucleobase_t::G
#undef T // nucleobase_t::T

#undef U // nucleos_union_t

Якось так.

Подякували: DianaSky1

4

Re: Кодування та декодування даних. з Java в c++

leofun01 написав:

Не зрозумів.

Один символ кодується чотирма, наприклад: ATGG
Перший з символів вказує його тип, Наприклад: А - спецсимвол (символи управління: \n, \t..., Розділові знаки: .,?... Математичні символи: +-/...), G - малі літери, С - великі літери, Т - решта (цифри, додаткові символи (грецікі літери, стрілки...). Три наступні символи (в нашому прикладі ТGG) це власне код символу.
Тобто, якщо не використовувати масив потрібно:
Для кодування :
1. Якось визначити тип символу. Гаразд, відрізнити велику||малу літеру, цифру не проблема. Запитання, що робити зі спецсимволами та додатковими символами?
2. Присвоїти символу відповідний тримимвольний код.
...
Для декодування
1. Якось розрізняти символи при декодуванні, адже одному трисимвольному кодові, відповідає 4 варіанти.

Як варіант спало на думку, якось створити відповідні таблиці символів, але цього я робити не вмію ;(

Подякували: leofun011

5

Re: Кодування та декодування даних. з Java в c++

DianaSky написав:

додаткові символи (грецікі літери, стрілки...).
.. що робити зі спецсимволами та додатковими символами? ..

Якщо ще й грецькі будуть, то треба визначитись з кодуванням вхідного тексту. Тоді в коді доведеться користувати wchar_t. І 4 символи { A, C, G, T } буде явно не достатньо.

6

Re: Кодування та декодування даних. з Java в c++

Достатньо, тому що за умовою завдання мова Українська, а грецька використовується не повністю, а лише для передачі альфа, бета, гама частинок. Основну масу четвертого блоку займають символи і оператори формул: різні там сталі планка, спін, ізоспін, гамільтоніан ядра, матриці Гел-Мана та ін.

Подякували: leofun011

7

Re: Кодування та декодування даних. з Java в c++

Вам тут узагалі не потрібні нуклеотиди та 4-вимірний масив. Вам треба або використовувати лише 4 значення (2 біти) з кожного байту, або, як вказав leofun01, пхати по 4 2-бітові коди в 1 байт.
Для кодування і декодування треба буде створити таблиці wchar_t => ваше кодування і ваше кодування => wchar_t, це найпростіше.

Подякували: leofun011

8

Re: Кодування та декодування даних. з Java в c++

хм.. вручну порахував, дійсно, всіх їх (латинська, грецька, україньска, оператори, пунктуація) можна втиснути в 8 біт, якщо є бажання. Ще й для графічних символів місце знайдеться. Але це якщо повністю користувати тільки це розроблене кодування без конвертації. Для конвертації вилізе wchar_t або ще якийсь тип даних розміру більшого ніж 1 байт.

Але я поки не бачу як це має виглядати з умовою

DianaSky написав:

Перший з символів вказує його тип, Наприклад: А - спецсимвол (символи управління: \n, \t..., Розділові знаки: .,?... Математичні символи: +-/...), G - малі літери, С - великі літери, Т - решта (цифри, додаткові символи (грецікі літери, стрілки...). Три наступні символи (в нашому прикладі ТGG) це власне код символу.

Попробую їх погрупувати. Може щось із того вийде..

9

Re: Кодування та декодування даних. з Java в c++

koala написав:

Вам тут узагалі не потрібні нуклеотиди та 4-вимірний масив. Вам треба або використовувати лише 4 значення (2 біти) з кожного байту, або, як вказав leofun01, пхати по 4 2-бітові коди в 1 байт.
Для кодування і декодування треба буде створити таблиці wchar_t => ваше кодування і ваше кодування => wchar_t, це найпростіше.

4-вимірний масив фіксованого розміру розміщується в пам'яті так само, як 1-вимірний, тому це не настільки принципово. Якщо ми хочемо максимально використати вже написаний код, то 4-вимірний масив символів, яким це кодування описується, можна переписати, наприклад, так:

wchar_t symbol [4][4][4][4]={
        //A
        {
            //A
            {
                //A
                {
                    //A,G,C,T
                    L' ', L'\n', L'\t', L'`'
                },

Рядки тексту можна представити як wchar_t*, рядки нуклеотидів — як char*; додавання рядків замінити на strcat() чи примітивні операції з рядком як масивом символів, і т.д. Тобто, в принципі, увесь цей код можна переписати в сішному стилі, суттєво не змінюючи його логіку.

Наскільки цей код оптимальний (особливо коли робиться перекодування з символів у нуклеотиди шляхом перебору) — окреме питання. Але, принаймні, він достатньо простий, щоб його можна було перекласти на будь-яку іншу мову.

Подякували: leofun011