2015-12-24 2 views
2

У меня возникает эта проблема прямо сейчас, когда вы решаете проблему (практика для java). Проблема заключается в том, чтобы скобки ввода были в правильном порядке (дополнительная информация по этой ссылке: http://www.codeabbey.com/index/task_view/matching-brackets). Проблема, с которой я столкнулся, заключается в том, что мой буферизованный считыватель не будет читать мою последнюю строку ввода. Он превращает его в конечный цикл, но, кажется, «приостанавливается» перед его чтением. Единственный способ, с помощью которого я могу заставить его работать, - это нажать кнопку ввода, а затем программа продолжит работу с enter.readLine() в последний раз и распечатает мою строку. Вот мой код:BufferedReader не будет читать окончательную строку ввода

public static void main(String[] args) 
{ 

    try 
    { 
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 
    System.out.println("input data:"); 
    //First line is read to take in the number of lines for input will follow 
    int data = Integer.parseInt(input.readLine()); 

    int i = 0; 

    while(i < data) 
    { 
    //temp string builder to hold the wanted characters 
    StringBuilder stringy = new StringBuilder(); 
    String line = input.readLine(); 
    //temp string builder holding the entire line 
    StringBuilder sb = new StringBuilder(line); 
     for(int j = 0; j < sb.length(); j++) 
     { 
      //loops through string builder & adds the wanted characters to stringy 
      switch(sb.charAt(j)){ 
      case '(' : stringy.append(sb.charAt(j)); 
      break; 

      case ')' : stringy.append(sb.charAt(j)); 
      break; 

      case ']' : stringy.append(sb.charAt(j)); 
      break; 

      case '[' : stringy.append(sb.charAt(j)); 
      break; 

      case '{' : stringy.append(sb.charAt(j)); 
      break; 

      case '}' : stringy.append(sb.charAt(j)); 
      break; 
      } 
     } 
     System.out.println(stringy); 

     i++; 
    } 
    }catch(IOException x) 
    { 
     x.printStackTrace(); 
    } 

} 

Извините, если я недостаточно ясен. Я попытался прочитать это онлайн, но у людей нет такой специфической проблемы. Я не уверен, как, но кажется, что перед моей последней строкой ввода добавлена ​​дополнительная строка или что-то еще. Спасибо за помощь, я очень ценю это.

Редактировать: Извините, я понимаю, что я не представил никаких входных данных для программы. Вот оно:

4 
(a+[b*c]-{d/3}) 
(a + [b * c) - 17] 
((a * x) + [b] * y) + c 
auf(zlo)men [gy<psy>] four{s} 

Просто скопируйте и вставьте выше, в вашей программе, и вы будете видеть проблему

+1

Программа работает правильно. Например, если вы введете '5' в первую' readLine() '(данные), тогда он попросит у вас 5 новых значений для соответствующих скобок. Каждый раз вам нужно нажать «enter» один раз, чтобы предоставить эти 5 входов. Итак, в чем проблема? –

+0

его работа хорошая проверка это http://ideone.com/uo8gN3 –

+0

К сожалению, я не представил входную информацию, которую я использовал. Я полагал, что это может быть связано с копированием и вводом ввода в область сервера. –

ответ

1

Резюме

В BufferedReader#readLine методе блоков на I/O чтения ввода до тех пор, пока не найдет символ конца строки на входе. Последняя строка вашего ввода отличается от всех остальных строк тем, что в конце не имеет символа терминатора линии. Нажатие ввода в терминал добавляет требуемый символ терминатора линии, но в качестве побочного эффекта он также заставляет терминал продвигать курсор вниз по строке, вызывая замеченные «пробелы между линиями». Это не неожиданное поведение, и это не ошибка в коде, но вы можете «исправить» его, убедившись, что у вас есть символ конца строки в конце последней строки вашего ввода.

ПОДРОБНО.Подробнее

я могу воспроизвести поведение, которое вы описали. Я компилирую код, запускаю его и вставляю в образец ввода. Как и вы сказали, он висит на последней строке. Затем я нажимаю Enter, что заставляет его действовать, но зачем это нужно? Существует также неожиданный разрыв перед последним результатом.

> java Test 
input data: 
4 
(a+[b*c]-{d/3}) 
(a + [b * c) - 17] 
((a * x) + [b] * y) + c 
auf(zlo)men [gy<psy>] four{s}([]{}) 
([)] 
(()[]) 

()[]{} 

Я также заметил еще одну проблему, о которой вы не упомянули. В седьмой строке в приведенном выше примере (строка, начинающаяся с «auf»), результат был напечатан сразу после перехода на новую строку.

Эй, что здесь происходит? Ну, давайте попробуем применить некоторые методы отладки. jstack - это инструмент, который поставляется с JDK, который позволяет подключаться к запущенной JVM и выгружать состояние его потоков выполнения. Это отличный способ взглянуть на то, что ваш код действительно делает, когда он работает. Попробуем запустить jstack прямо, когда процесс, похоже, зависает. Во-первых, мне нужно идентифицировать идентификатор процесса JVM. Для этого воспользуемся jps.

> jps 
83518 Test 

> jstack 83518 
2015-12-24 21:25:17 
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.65-b04 mixed mode): 

... 

"main" prio=5 tid=0x00007fbba2001000 nid=0x1903 runnable [0x000000010a560000] 
    java.lang.Thread.State: RUNNABLE 
    at java.io.FileInputStream.readBytes(Native Method) 
    at java.io.FileInputStream.read(FileInputStream.java:272) 
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:273) 
    at java.io.BufferedInputStream.read(BufferedInputStream.java:334) 
    - locked <0x00000007aaa9a5f0> (a java.io.BufferedInputStream) 
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283) 
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325) 
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177) 
    - locked <0x00000007aab2ad88> (a java.io.InputStreamReader) 
    at java.io.InputStreamReader.read(InputStreamReader.java:184) 
    at java.io.BufferedReader.fill(BufferedReader.java:154) 
    at java.io.BufferedReader.readLine(BufferedReader.java:317) 
    - locked <0x00000007aab2ad88> (a java.io.InputStreamReader) 
    at java.io.BufferedReader.readLine(BufferedReader.java:382) 
    at Test.main(Test.java:22) 

... 

Я урезал вывод jstack, чтобы показать только соответствующую основную нить. Это интересно. Я вижу основную точку входа: Test.main. Я могу позвонить по телефону BufferedReader#readLine. После ряда других вызовов метода он попадает в FileInputStream#read. Если я запускаю jstack несколько раз, я продолжаю видеть то же самое. Это означает, что выполнение задерживается в этом методе, пытаясь прочитать байты из ввода. Странно. Что бы это объясняло? Возможно, JavaDocs для BufferedReader#readLine содержит некоторое объяснение поведения.

Считывает текст. Линия считается завершенной любым из строк ('\ n'), возвратом каретки ('\ r') или возвратом каретки, за которым следует сразу строка.

На этом этапе давайте попробуем сформировать гипотезу. Что может заставить процесс застревать, пытаясь читать данные? JavaDocs говорят, что строка считается завершенной конкретным символом. Возможно, наша заключительная строка ввода не содержит символа завершения строки.

Чтобы подтвердить эту теорию, давайте попробуем взглянуть на дамп hexadecimal нашего ввода. Для этого я обычно использую инструмент командной строки xxd. Вот результаты.

0000000: 340a 2861 2b5b 622a 635d 2d7b 642f 337d 4.(a+[b*c]-{d/3} 
0000010: 2920 0a28 6120 2b20 5b62 202a 2063 2920 ) .(a + [b * c) 
0000020: 2d20 3137 5d0a 2828 6120 2a20 7829 202b - 17].((a * x) + 
0000030: 205b 625d 202a 2079 2920 2b20 630a 6175 [b] * y) + c.au 
0000040: 6628 7a6c 6f29 6d65 6e20 5b67 793c 7073 f(zlo)men [gy<ps 
0000050: 793e 5d20 666f 7572 7b73 7d    y>] four{s} 

Я тестирую на Mac, который использует один управляющий символ, LF (перевод строки), чтобы указать на новую строку. Это может быть другим на других платформах. В первую очередь, Windows использует последовательность из двух управляющих символов: CR/LF (возврат каретки/линия). Согласно стандарту Unicode, код ASCII для LF равен 0a в шестнадцатеричном представлении. Это показано в кодовой таблице Basic Latin(ASCII). Возвращаясь к нашему шестнадцатеричному дампу, мы можем видеть 4 вхождения символа 0a и отметить, что в конце последней строки нет символа 0a.

Это начинает выглядеть многообещающей теорией. Что еще мы можем сделать, чтобы проверить это? Благодаря OpenJDK, мы можем просмотреть реализацию исходного кода многих обычных классов JDK, включая BufferedReader. Попробуем посмотреть на реализацию BufferedReader#readLine. Это довольно сложный цикл, но нижняя строка заключается в том, что он отслеживает «конец строки» в переменной с именем eol, и это условие, из-за которого он перестает заполнять свой внутренний буфер в методе fill и вместо этого возвращает строку в вызывающий абонент.

charLoop: 
    for (i = nextChar; i < nChars; i++) { 
     c = cb[i]; 
     if ((c == '\n') || (c == '\r')) { 
      eol = true; 
      break charLoop; 
     } 
    } 

    startChar = nextChar; 
    nextChar = i; 

    if (eol) { 
     String str; 
     if (s == null) { 
      str = new String(cb, startChar, i - startChar); 
     } else { 
      s.append(cb, startChar, i - startChar); 
      str = s.toString(); 
     } 
     nextChar++; 
     if (c == '\r') { 
      skipLF = true; 
     } 
     return str; 
    } 

ОК, теперь я убежден! Давайте проверим гипотезу, повторив наш оригинальный тест, но на этот раз давайте удостовериться, что у нас есть терминатор линии в конце нашей последней строки. Скопируйте в эту версию ввода, я теперь вижу эти результаты.

> java Test 
input data: 
4 
(a+[b*c]-{d/3}) 
(a + [b * c) - 17] 
((a * x) + [b] * y) + c 
auf(zlo)men [gy<psy>] four{s} 
([]{}) 
([)] 
(()[]) 
()[]{} 

Это больше похоже на это!

+0

Ничего себе, большое спасибо за этот ответ. Это объяснение было именно тем, что мне нужно.Я определенно планирую использовать эти инструменты в будущем, чтобы искать проблемы в своем коде, я серьезно не знал, что они существуют! Наверное, довольно легко сказать, что я новичок-программист, но буду использовать эти инструменты в будущем, чтобы настроить свои навыки. Еще раз благодарю вас за этот ответ, вы действительно прояснили мне много чего. –

+0

@DaveCooney, я рад, что это помогло! Не беспокойся. Мы все были новичками. :-) Если это было полезно, пожалуйста, подумайте о принятии ответа и/или о повышении. –

Смежные вопросы