Страницы

Поиск по вопросам

Показаны сообщения с ярлыком ввод. Показать все сообщения
Показаны сообщения с ярлыком ввод. Показать все сообщения

пятница, 14 февраля 2020 г.

JAVA: Проверка входных данных, Рекурсия, Исключения

#java #исключения #рекурсия #ввод


Такая проблемка возникла:

Нужно чтобы пользователь вводил число.
Если число не int (например буква), то должно выбрасываться исключение. 
А я как программист должен сделать так, чтобы программа не завершалась и не "пропускала"
пользователя дальше, пока он не введёт корректное значение.

Пробовал через рекурсию. Но тк в стеке творится неведомая **** (на скрине), думаю
этот способ не лучший. 

Посоветуйте что сделать

При корректировке моего кода, учитывайте 1 и 2 задание лабораторной (на скрине)




    


Ответы

Ответ 1



Одно из решений - цикл while. boolean check = true; int fN; while(check) { try { Scanner sc = new Scanner(System.in); check = false; //ставим false, что бы не вводить больше данные System.out.println(...); fN = sc.nextInt(); } catch(Exception ex) { System.out.println(...); check = true; //если вышло исключение, ставим обратно true, что бы опять вводить данные } }

Ответ 2



Нормальный способ. Просто разделите вывод сообщения об ошибке и рекурсивный вызов функции небольшой задержкой, типа Thread.sleep(20);

Ответ 3



Может как-то так попробовать: public static void main(String[] args) throws Exception { System.out.println(InputFirstNumber()); } static int InputFirstNumber() throws IOException { try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) { try { while (true) { System.out.println("Input first number!"); return Integer.parseInt(bufferedReader.readLine()); } } catch (NumberFormatException ex) { System.err.println("\tError!"); System.err.println("\tIncorrect data!"); return InputFirstNumber(); } } }

Ответ 4



Решил таким способом (скрин) В итоге от try и catch пришлось отказаться. Хотя я думаю если добавить Thread.sleep(20); (как советовал тут один человек) То мой изначальный код с рекурсией, будет работать правильно Всем спасибо за помощь) Поставил лайки, но тк у меня рейтинг ниже 15, они кажется не отобразятся......

пятница, 31 января 2020 г.

Как ввести последовательность чисел, записанных в строку, в массив

#python #python_3x #python_32 #ввод


Дана строка: 1 3 9 3 2. На C++ это выглядело бы так:

for(size_t i = 0; i < 5; i++)
    std::cin >> b[i];


А как сделать это на Python?
    


Ответы

Ответ 1



Можно воспользоваться генератором списков: In [2]: xs = [int(x) for x in input().split()] 1 3 9 3 2 In [3]: xs Out[3]: [1, 3, 9, 3, 2] Можно воспользоваться функцией map (Python 3.x): In [4]: xs = list(map(int, input().split())) 1 3 9 3 2 In [5]: xs Out[5]: [1, 3, 9, 3, 2] В случае Python 2.x вызов list не нужен: In [6]: xs = map(int, raw_input().split()) 1 3 9 3 2 In [7]: xs Out[7]: [1, 3, 9, 3, 2]

понедельник, 30 декабря 2019 г.

Некорректное чтение строки из std::cin после чтения числового значения

#cpp #ввод


При считывании потока из командной строки в переменную с помощью std::getline не
дает ввести данные, перескакивает. Как можно считать строку с пробелами в переменную
избежав моей проблемы в std::getline   

std::string  fio;
std::string  citi;
int id;

std::cout << "Введите id(число) абонента: ";
std::cin >> id;

std::cout << "Введите ФИО абонента: ";
std::getline(std::cin, fio, '\n');

std::cout <<"Введите город абонента: ";
std::cin >> citi;


ВЫВОД:
добавление абонента в группу пользователей

Введите id(число) абонента: 12
Введите ФИО абонента: Введите город абонента:

    


Ответы

Ответ 1



Вставьте строку #include //... std::cout << "Введите id(число) абонента: "; std::cin >> id; std::cin.ignore( std::numeric_limits::max(), '\n' ); std::cout << "Введите ФИО абонента: "; std::getline(std::cin, fio, '\n'); Проблема заключается в том, что в буфере ввода после использования оператора operator >> остается символ новой строки, соответствующий нажатой клавише Enter. А функция std;:getline читает буфер, пока не встретится этот символ. Поэтому если его не удалить, то будет считана пустая строка.

Ответ 2



Потому что после ввода числа в буфере остается символ '\n'. Он и считывается при вводе строки как пустая строка. Вам надо сбросить содержимое буфера перед вводом строки: cin.ignore(std::numeric_limits::max(), '\n'); При неверном вводе числа нужно еще сбросить флаг состояния ошибки cin.clear().

Ответ 3



(std::cin >> id).get(); Нужно проигнорировать символ переноса строки, потому что он остается и тогда getline читает пока не встретит этот символ и в итоге считывается пустая строка.

пятница, 27 декабря 2019 г.

Ввод/вывод в консоли, C++

#cpp #visual_studio_2015 #консоль #вывод #ввод


Здравствуйте.

Решил написать небольшую RPG-игру с псевдографикой в консоли. 
Для считывания нажатий клавиш использовал функцию GetAsyncKeyState из Windows.h

bool isKeyPressed(int virtualKeyCode)
{
    short keyState = GetAsyncKeyState(virtualKeyCode);
    return ((keyState & 0x8000) > 0);
}


В функции Update проверяю состояние клавиш и изменяю направления движения героя.

 void Update()
    {
    if(_kbhit())
    {   if (isKeyPressed('W'))
        {
            unitsArr[heroIndex].changeMoveDirectionTo(0, -1);
            moveUnitTo(&unitsArr[heroIndex]);
        }
        else if (isKeyPressed('S'))
        {
            unitsArr[heroIndex].changeMoveDirectionTo(0, 1);
            moveUnitTo(&unitsArr[heroIndex]);

        }
        else if (isKeyPressed('A'))
        {
            unitsArr[heroIndex].changeMoveDirectionTo(-1, 0);
            moveUnitTo(&unitsArr[heroIndex]);

        }
        else if (isKeyPressed('D'))
        {
            unitsArr[heroIndex].changeMoveDirectionTo(1, 0);
            moveUnitTo(&unitsArr[heroIndex]);
        }
    ...
    }


После этого захотел написать функцию, которая выводила бы на экран вопрос, и при
помощи _getch() считывала бы ответ игрока (y/n)

bool getAnswerFromLogPanel(const string questionMessage)
{
    UpdateLog(questionMessage + " [Y]/[N]");

    const char inputAnswer = tolower(_getch());
    if (inputAnswer == 'y')
    {
        UpdateLog("[Y]");
        return true;
    }

    UpdateLog("[N]");
    return false;
}


Здесь столкнулся с проблемой, что _getch() не останавливает поток и не ждет нажатия
клавиши.

При этом если использовать вместо _getch() функцию getchar() или cin.get() на экран
консоли выводятся символы ранее нажатых клавиш.





Как я понял,_getch() просто считывает один символ из последних нажатых клавиш (те,
которые выводит на экран getchar() или cin.get()) и поэтому не останавливает поток.

То что мне не помогло:

cin.ignore(), cin.clear(), cin.sync(), system("cls"), fflush(stdin).

То что работает, но не так как надо:


Работает, но если до этого когда-то была нажата клавиша Y или N - ответ будет считываться
с нее.

do
{
    char input = _getch();
    input = tolower(input);

    if (input == 'y')
   {
       UpdateLog("[Y]");
       return true;
   }

    if(input == 'n')
    {
        UpdateLog("[N]");
        return false;
    }
} while (true);

При каждом срабатывании _kbhit() считывать при помощи _getch() символ с потока.
Но тогда движение героя и реакция на нажатия клавиш значительно замедляется.


C++, Visual Studio 2015
    


Ответы

Ответ 1



Поскольку потоковое чтение работает в конечном итоге через WinAPI-шные функции и не ожидает, что будет использован прямой доступ к тем же функциям, то оно не дружит с низкоуровневым вводом через GetAsyncKeyState. Поэтому, если уж вы пользуетесь низкоуровневыми функциями, пользуйтесь ими всё время. Для вашего случая, вам должны помочь FlushConsoleInputBuffer (чтобы сбросить буферизацию уже нажатых к текущему моменту клавиш) и ReadConsoleInput. Вот общая страница документации, на всякий случай.

среда, 25 декабря 2019 г.

Java Линукс/Win консольное прослушивание нажатия клавиатуры

#java #консоль #ввод #клавиатура #listener


Пишу Java консольное приложение для Линукс и Виндовс, которое одновременно прослушивает
нажатие клавиатуры и выводит информацию (без нажатия клавиши Enter для принятия ввода
текста).

Как это можно сделать?

Знаю про JNI, Jline, JavaCurces но нет навыков их использования, хотелось бы сделать
все средствами Java.
    


Ответы

Ответ 1



Одной из ключевых особенностей Java является написание кроссплатформенных программ. Для получения одинакового результата в разных операционных системах Java выполняет разный код в разных ОС. Упомянутые Вами программы это именно именно такие обёртки над системными функциями. Если кроссплатформенность хоть сколько-нибудь важна, лучше использовать их. Из JLine FAQ: How does JLine work? On Windows, JLine uses a native .dll (which it automatically extracts from the jline jar and loads at runtime) to access native console features. On UNIX systems, JLine will perform the necessary terminal setup by launching the "stty" command.

Ответ 2



На данный момент, я нашел решение с использованием jNativeHook. На Windows еще не тестировал, на Alt Linux работает хорошо. Осталось только сделоть прослушку клавиш не глобальгно, а только для окна консоли. package test; import java.io.IOException; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; import org.jnativehook.GlobalScreen; import org.jnativehook.NativeHookException; import org.jnativehook.keyboard.NativeKeyEvent; import org.jnativehook.keyboard.NativeKeyListener; public class Test0 implements NativeKeyListener { public static void main(String[] args) throws IOException { for (Handler handler : Logger.getLogger("").getHandlers()) handler.setLevel(Level.OFF); try { GlobalScreen.registerNativeHook(); } catch (NativeHookException ex) { System.exit(1); } GlobalScreen.addNativeKeyListener(new Test0()); } public void nativeKeyPressed(NativeKeyEvent e) { System.out.println(NativeKeyEvent.getKeyText(e.getKeyCode()).toLowerCase()); } public void nativeKeyReleased(NativeKeyEvent e) { } public void nativeKeyTyped(NativeKeyEvent e) { } } Все еще надеюсь найти лучшее решение, или сделать прослушку не глобальной.

Ответ 3



Такой вопрос уже был на stackoverflow: Equivalent function to C's “_getch()” in Java? Вот исходный код на ваш вопрос. Опубликованный в посте: public static void getCh() { final JFrame frame = new JFrame(); synchronized (frame) { frame.setUndecorated(true); frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME); frame.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { synchronized (frame) { frame.setVisible(false); frame.dispose(); frame.notify(); } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } }); frame.setVisible(true); try { frame.wait(); } catch (InterruptedException e1) { } } }

Ответ 4



Эт уже руткит получается. В линухе так получится отслеживать только того, из под которого запущена прога. Да и то вряд-ли.

среда, 18 декабря 2019 г.

“Странный” символ в конце файла

#c #файлы #ввод


Написал программку для копирования содержимого txt файла из 1 в 2. Почти всё работает,
только я не понимаю как пофиксить запись последнего символа?

#include 
#include 

#define size 101


int main()
{
FILE* read;
FILE* write;

read = fopen("1.txt", "r");
write = fopen("2.txt", "w");

char buffer[size];

char c;



if(read != NULL)
{
   while(c != EOF)
   {
       c = getc(read);
       fprintf(write,"%c", c);
   }

   fclose(read);
   fclose(write);
}

else
{
    printf("File is doesn't exist\n");
}



    


Ответы

Ответ 1



Вы объявляете переменную c, потом проверяете у нее значение, а потом инициализируете. При этом, если getc() вернула EOF вы все равно вызываете запись этого символа в файл fprintf(write,"%c", c); Вам нужно переписать цикл к нормальному виду c = getc(read); while(c != EOF) { fprintf(write,"%c", c); c = getc(read); } При этом переменную c нужно объявить не как char, а как int. Иначе цикл у вас будет прекращаться, как только в файле встретится с кодом 255 (в кодировке Win1251 это буква я).

Ответ 2



char c; Неверно. EOF имеет тип int, когда его урезаешь до char, старшие байты теряются и будет некий символ, который будет ошибочно рассматриваться как EOF (буква я в win1251). while(c != EOF) Не инициализированную переменную сравнивать с чем-то - плохая идея. c = getc(read); fprintf(write,"%c", c); Прочитали символ и вывели. Неизвестно, успешно прочитали или нет - сравнение с EOF будет уже потом, после того, как произойдёт его вывод. При достижении EOF выводится лишняя буква я. Вот правильный код: for (int c; (c=getc(read)) != EOF; ) fprintf(write, "%c", c); Кстати fprintf(write,"%c", c); можно заменить на putc(c, write), но тут по желанию.

Ответ 3



Все не просто просто,а очень просто :) int c; ... while((c = getc(read)) != EOF) { fprintf(write,"%c", c); }

четверг, 5 декабря 2019 г.

Отловить сочетание клавиш в консоли

#cpp #консоль #ввод


1) Код должен быть или кроссплатформенный, или 2а варианта кода (под Windows и Linux)

2) Мне нужно отследить, когда пользователь нажмет Shift+Enter 

3) Программа консольная
    


Ответы

Ответ 1



Можно так: #include #include #include #include #include template void throw_if(T val, T err, const char* msg) { if (val == err) { throw std::runtime_error(msg); } } template void throw_if_not(T val, T ok, const char* msg) { if (val != ok) { throw std::runtime_error(msg); } } enum class Key_t { Unknown, Shift, Return, Esc }; #if defined(_MSC_VER) #include Key_t to_Key_t(WORD vk) { switch (vk) { case VK_SHIFT: return Key_t::Shift; case VK_RETURN: return Key_t::Return; case VK_ESCAPE: return Key_t::Esc; default: return Key_t::Unknown; } } void read_kb(std::function key_handler) { auto stdout_handle = GetStdHandle(STD_INPUT_HANDLE); throw_if(stdout_handle, INVALID_HANDLE_VALUE, "could not get STD_INPUT_HANDLE"); DWORD orig_mode; throw_if(GetConsoleMode(stdout_handle, &orig_mode), FALSE, "could not get console mode"); throw_if(SetConsoleMode(stdout_handle, orig_mode | ENABLE_WINDOW_INPUT), FALSE, "could not set console mode"); try { for (bool done = false; !done; ) { std::array ir; DWORD count; throw_if(ReadConsoleInput(stdout_handle, ir.data(), ir.size(), &count), FALSE, "coud not read console input"); std::for_each(std::cbegin(ir), std::cbegin(ir) + count, [&done, key_handler](const INPUT_RECORD& r) { if (r.EventType == KEY_EVENT) { const auto& e = r.Event.KeyEvent; done = key_handler(to_Key_t(e.wVirtualKeyCode), e.bKeyDown); } }); } } catch (...) { SetConsoleMode(stdout_handle, orig_mode); throw; } SetConsoleMode(stdout_handle, orig_mode); } #else #include #include #include #include #include bool is_a_console(int fd) { char arg = 0; return (isatty(fd) && ioctl(fd, KDGKBTYPE, &arg) == 0 && ((arg == KB_101) || (arg == KB_84))); } int open_a_console(const char *fn) { int fd = open(fn, O_RDWR); if (fd < 0) { fd = open(fn, O_WRONLY); } if (fd < 0) { fd = open(fn, O_RDONLY); } if (fd < 0) { return -1; } return fd; } int getfd() { int fd; std::vector fn = { "/proc/self/fd/0", "/dev/tty", "/dev/tty0", "/dev/vc/0", "/dev/systty", "/dev/console" }; for (const auto& s : fn) { fd = open_a_console(s); if (is_a_console(fd)) { return fd; } close(fd); } for (fd = 0; fd < 3; fd +=1) if (is_a_console(fd)) { return fd; } throw std::runtime_error("could not get console fd"); } Key_t to_Key_t(const char c) { switch (c) { case 1: return Key_t::Esc; case 42: case 54: return Key_t::Shift; default: return Key_t::Unknown; } } void read_kb(std::function key_handler) { int fd = getfd(); termios orig; throw_if_not(tcgetattr(fd, &orig), 0, "could not get attr"); int kbmode_orig; throw_if_not(ioctl(fd, KDGKBMODE, &kbmode_orig), 0, "could not get KDGKBMODE"); termios raw = orig; raw.c_lflag &= ~(ECHO | ICANON); raw.c_cc[VMIN] = 0; raw.c_cc[VTIME] = 1; tcsetattr(fd, TCSANOW, &raw); throw_if_not(ioctl(fd, KDSKBMODE, K_RAW), 0, "could not set KDSKBMODE"); try { for (bool done = false; !done; ) { char c = 0; if (read(fd, &c, 1) == 1) { done = key_handler(to_Key_t(c & 0x7F), !(c & 0x80)); } } } catch (...) { tcsetattr(fd, TCSANOW, &orig); ioctl(fd, KDSKBMODE, kbmode_orig); throw; } tcsetattr(fd, TCSANOW, &orig); ioctl(fd, KDSKBMODE, kbmode_orig); } #endif bool is_Shift_Return(const std::set& keys) { return keys.size() == 2 && keys.find(Key_t::Shift) != std::end(keys) && keys.find(Key_t::Return) != std::end(keys); } int main() { try { std::set keys; read_kb([&keys](Key_t key, bool is_down) { if (is_down) { keys.insert(key); } else { keys.erase(key); } std::cout << (is_Shift_Return(keys) ? "Shift+Return" : "Unknown") << " key is " << (is_down ? "down" : "up") << std::endl; return (key == Key_t::Esc); }); } catch (const std::exception& e) { std::cout << "Error: " << e.what() << std::endl; return 1; } return 0; } Проверено на Win 10, Ubintu 16.04. В обычном режиме коды специальных клавиш (Shift, Alt, Ctrl, и т.п.) получить не удастся, т.к. ввод буферизируется и транслируется в символы (или строки). Поэтому консоль переводится в "сырой" режим (без буферизации и трансляции). Коды клавиш: Windows - Virtula-Key Codes, Linux - одним из способов Keyboard input. Работа с консолью в Windows - все достаточно тривиально, и описано в доках Reading Input Buffer Events. В Linux - см. ответ и ссылки из него - https://stackoverflow.com/a/29446193/2267114, плюс код утилиты showkey, плюс доступное описание кодов ioctl.

суббота, 13 июля 2019 г.

Ввод строки с помощью getch()

Здравствуйте, мне необходимо сделать функцию ввода строки, строка вводится до тех пор, пока пользователь не нажмет ENTER. Вот собственно сам код:
char* GetLine() { char* line = NULL; char ch; int i = 0; while(true){ ch = getch(); //Считываем, но не выводим символ switch(ch) { case '
': line = (char*)realloc(line, (i + 1) * sizeof(char)); line[i++] = '\0'; //Признак конца строки return line; case '\b': printf("\b \b"); //Удаляем символ в консоле if (i > 0) i--; break; default: putchar(ch); line = (char*)realloc(line, (i + 1) * sizeof(char)); line[i++] = ch; } } }
В чем собственно проблема, мне нужно, чтобы при нажатии отдельных клавиш (F1-F12, Esc, цифры на numpade и т.п) они не выводились в консоль. Я знаю, что можно свитчем сделать перебор всех клавиш сканкодом, но мне кажется должно быть решение полегче.


Ответ

В комментарии ответить - места не хватит...
В данном случае вас совершенно не должен волновать буфер ввода, так как вы все равно заканчиваете свой ввод нажатием Enter. Как его отрабатывает компилятор и операционная система - это их проблемы. Вот код -
#include #include #include
char * read() { size_t size = 8; char * buf = (char*)malloc(size*sizeof(char)); size_t count = 0;
for(int c = ' ' /*Неважно что, лишь бы не нуль */;c;) { c = getchar(); if (c == EOF || c == '
') c = '\0'; if (count == size) { buf = (char*)realloc(buf,size *= 2); } buf[count++] = c; } return buf; }
int main() { char * s = read(); printf("You wrote: [%s]
",s); free(s); }
Вводите хоть мегабайтную строку, лишь бы realloc отработал. Препод тут, я считаю, в корне неправ.
В случае getch() всякие функциональные клавиши дают 2 кода подряд, первый - 0 или 0xE0. Если видите такой код - считывайте второй код и игнорируйте их оба. Только вот о, скажем, русском языке при этом придется забыть...

понедельник, 3 декабря 2018 г.

Ввод/вывод в консоли, C++

Здравствуйте.
Решил написать небольшую RPG-игру с псевдографикой в консоли. Для считывания нажатий клавиш использовал функцию GetAsyncKeyState из Windows.h
bool isKeyPressed(int virtualKeyCode) { short keyState = GetAsyncKeyState(virtualKeyCode); return ((keyState & 0x8000) > 0); }
В функции Update проверяю состояние клавиш и изменяю направления движения героя.
void Update() { if(_kbhit()) { if (isKeyPressed('W')) { unitsArr[heroIndex].changeMoveDirectionTo(0, -1); moveUnitTo(&unitsArr[heroIndex]); } else if (isKeyPressed('S')) { unitsArr[heroIndex].changeMoveDirectionTo(0, 1); moveUnitTo(&unitsArr[heroIndex]);
} else if (isKeyPressed('A')) { unitsArr[heroIndex].changeMoveDirectionTo(-1, 0); moveUnitTo(&unitsArr[heroIndex]);
} else if (isKeyPressed('D')) { unitsArr[heroIndex].changeMoveDirectionTo(1, 0); moveUnitTo(&unitsArr[heroIndex]); } ... }
После этого захотел написать функцию, которая выводила бы на экран вопрос, и при помощи _getch() считывала бы ответ игрока (y/n)
bool getAnswerFromLogPanel(const string questionMessage) { UpdateLog(questionMessage + " [Y]/[N]");
const char inputAnswer = tolower(_getch()); if (inputAnswer == 'y') { UpdateLog("[Y]"); return true; }
UpdateLog("[N]"); return false; }
Здесь столкнулся с проблемой, что _getch() не останавливает поток и не ждет нажатия клавиши.
При этом если использовать вместо _getch() функцию getchar() или cin.get() на экран консоли выводятся символы ранее нажатых клавиш.


Как я понял,_getch() просто считывает один символ из последних нажатых клавиш (те, которые выводит на экран getchar() или cin.get()) и поэтому не останавливает поток.
То что мне не помогло:
cin.ignore(), cin.clear(), cin.sync(), system("cls"), fflush(stdin)
То что работает, но не так как надо:
Работает, но если до этого когда-то была нажата клавиша Y или N - ответ будет считываться с нее.
do { char input = _getch(); input = tolower(input);
if (input == 'y') { UpdateLog("[Y]"); return true; }
if(input == 'n') { UpdateLog("[N]"); return false; } } while (true); При каждом срабатывании _kbhit() считывать при помощи _getch() символ с потока. Но тогда движение героя и реакция на нажатия клавиш значительно замедляется.
C++, Visual Studio 2015


Ответ

Поскольку потоковое чтение работает в конечном итоге через WinAPI-шные функции и не ожидает, что будет использован прямой доступ к тем же функциям, то оно не дружит с низкоуровневым вводом через GetAsyncKeyState
Поэтому, если уж вы пользуетесь низкоуровневыми функциями, пользуйтесь ими всё время.
Для вашего случая, вам должны помочь FlushConsoleInputBuffer (чтобы сбросить буферизацию уже нажатых к текущему моменту клавиш) и ReadConsoleInput. Вот общая страница документации, на всякий случай.