2016-04-18 18 views
1

Ich arbeite an einem Windows 7-Rechner.Verwenden der Eingabeaufforderung mit Java

Ich arbeite an einer Anwendung, die eine Front für den GHCi-Interpreter für Haskell ist. Der Benutzer gibt einen Befehl ein, dann führt Java den Befehl über die exec() -Methode in Runtime aus, und dann zeigt die Anwendung den Text an, der angezeigt würde, wenn der Benutzer GHCi nur mit der Eingabeaufforderung ausführen würde.

Im Moment habe ich Probleme mit der Schleife, die die Ausgabe druckt.

Hier ist der Code, den ich gerade habe.

public class GHCiTest { 
public static Scanner rd, sc; 

/** 
* @param args the command line arguments 
*/ 
public static void main(String[] args) { 

try { 

    System.out.println("Starting... "); 

    Process p = Runtime.getRuntime().exec("ghci"); 

    PrintStream hugsin = new PrintStream(p.getOutputStream()); 
    InputStream hugsout = p.getInputStream(); 

    sc = new Scanner(hugsout); 
    rd = new Scanner(System.in); 

    String rdnextline; 



    while (true){ 
    while (sc.hasNextLine()){ 
     System.out.println(sc.nextLine()); 

    } 
     System.out.println("yay"); 
     rdnextline = rd.nextLine(); 
    if (rdnextline == "quit"){break;} 
    hugsin.println(rdnextline); 
    hugsin.flush(); 

    } 
    System.out.println(" ... successful completion."); 
} 
catch(IOException e) { 
    e.printStackTrace(); 
} 
} 

} 

Ich weiß, dass die anfängliche Start von GHCi arbeitet, weil das Programm den Ausdruck „GHCi, Version 7.10.3: http://www.haskell.org/ghc/: Hilfe“. Das Problem scheint jedoch die while-Schleife (sc.hasNextLine()) zu sein, die die Ausgabe der Eingabeaufforderung lesen und ausgeben soll, bis nichts mehr übrig ist, da sie nicht aus der Schleife ausbrechen und mit fortfahren wird lese die Benutzereingabe. Ich weiß das, weil das Programm nicht das "Yay" -Flag druckt, das ich nach der Schleife eingegeben habe.

+0

Haben Sie versucht, einen gepufferten Leser anstelle von Scanner zu verwenden? – Norsk

+2

Weil 'sc.hasNextLine()' wartet, bis das ** Ende des Streams ** erreicht wurde (wenn keine Eingabe erfolgt) ... Und das Ende des Streams wird nur passieren, wenn das Programm beendet wird. – Codebender

+1

Zwei Bedenken: 1. GHCi ist nicht wirklich so konzipiert, um so verwendet zu werden. Es ist ein interaktives Entwicklungswerkzeug. Wenn Sie sich auf Details ihrer interaktiven Benutzeroberfläche verlassen, kann Ihr Programm zum Erliegen kommen, wenn eine neue Version herauskommt. Könnten Sie einfach 'ghc -e' für Ihre Zwecke verwenden? 2. Sie sollten GHCi nicht dem Web aussetzen, es sei denn, Sie haben eine große Sandbox um es herum; voller GHCi-Zugriff ist wie voller Shell-Zugriff. – dfeuer

Antwort

2

Ihre Schleife wird nicht beendet, bis das Ende des Stroms erreicht wurde:

while (sc.hasNextLine()){ 
    System.out.println(sc.nextLine()); 
} 

Das Ende des Stroms das Ende des Prozesses ist. Ihr Java-Programm wartet also darauf, dass der Unterprozess vollständig ausgeführt wird und beendet wird. Sobald dies geschieht, wird die Schleife beendet und das Java-Programm sendet die gewünschten Befehle an den Prozess.

Sorry, ich meine, versuchen Sie, die gewünschten Befehle an den Prozess zu senden; Es wird nicht erfolgreich sein, da der Prozess beendet wurde.

Wenn der GHCi-Prozess eine "Aufforderung" irgendeiner Art ausgibt, könnten Sie versuchen, Ihre while(...) { print } in diesem Moment zu brechen, eine Eingabe vom Benutzer zu erhalten, diese an den Prozess zu senden und dann die while(...) { print } erneut einzugeben , auf die nächste Aufforderung wartend.

Wenn die Eingabeaufforderung nicht mit einem Zeilenumbruch endet, sondern am Anfang einer Zeile erscheint, in der die Benutzereingabe eingegeben wird, können Sie keine while(sc.hasNextLine()) { ... } Art von Schleife verwenden, da die Eingabeaufforderung keine vollständige Zeile ist. Möglicherweise müssen Sie auf Zeichen für Zeichen zurückgreifen und nach der Eingabeaufforderung in den letzten "n" Zeichen suchen.

Sieht so aus, als könnten Sie die Eingabeaufforderung in GHCi ändern. Siehe here for details. Wenn Sie die Eingabeaufforderung so ändern, dass sie mit einem Zeilenende endet, können Sie den Stream weiterhin in Zeilen lesen.

while (sc.hasNextLine()){ 
    String line = sc.nextLine(); 
    if (line.equals("YourPromptHere")) 
     break; 
    System.out.println(line); 
} 

(Alternativ könnten Sie in der Lage sein, etwas mit Threads tun beiden Teile zu ermöglichen, ohne blockieren sie zu laufen. Natürlich Threading kommt mit seinen eigenen Problemen und Komplexität.)


EDIT

Ich hatte einen blendenden Blitz des Offensichtlichen. GHC der Eingabeaufforderung Unter der Annahme, sieht wie folgt aus ...

GHCi, version 7.10.3 
yada, yada, yada ... 
Main> _ 

... Sie das Trennzeichen des Scanners einstellen könnten Main> der Prompt-String zu sein.

// Set scanner delimiter to GHCi's Prompt string 
sc = new Scanner(hugsout).setDelimiter("^Main> "); 

while (sc.hasNext()) { 

    // Echo GHCi's output upto the delimiter (prompt) 
    System.out.println(sc.next()); 

    // Read user input & transfer to GHCi. 
    System.out.print("Replacement Prompt> "); 
    rdnextline = rd.nextLine(); 
    if (rdnextline == "quit") { 
     break; 
    } 
    hugsin.println(rdnextline); 
    hugsin.flush(); 
} 

Hinweis: Dies gilt nicht berücksichtigt, die sekundäre Eingabeaufforderung verwendet, wenn GHCi mehr Input erwartet den Befehl abzuschließen. Sie könnten eine Regex-Datei wie "^Main> |\bAlt> " verwenden, die mit einer Eingabeaufforderung übereinstimmt, aber Sie können nicht feststellen, an welcher Eingabeaufforderung das Trennzeichen angeglichen wurde. Der erste Teilausdruck "^Main> " stimmt mit dem Anfang einer Zeile überein, gefolgt von "Main>", wobei der zweite Teilausdruck "\bAlt> " nur eine Wortgrenze gefolgt von "Alt>" entspricht. Dies liegt daran, dass der Ausgabestrom des GHCi wie "\nMain> Alt> " mit einer langen Pause vor dem Alt> aussehen würde; die "newline" vor Alt> würde normalerweise von dem Echo des Enter keypressed auf dem Eingabestream kommen.

+0

Wissen Sie, wie ich alles drucken lassen könnte, bis der Benutzer die Eingabe eingeben muss? – dinstruction

+0

Beobachten Sie den Ausgabestream und suchen Sie nach einer Eingabeaufforderung von 'GHCi'. Siehe edit – AJNeufeld

+0

Solltest du sagen, nachdem ich eine neue Zeile erhalten habe, sollte ich prüfen, ob sie gleich "Main>" ist, was GHCi druckt, bevor Benutzereingaben angefordert werden? Gibt es eine allgemeine Lösung, um festzustellen, ob der Scanner das nächste Zeichen in einem InputStream blockiert? – dinstruction

2

Empfangen Sie die Ausgabe von Ghci in einem anderen Thread wie diesem.

System.out.println("Starting... "); 

Process p = Runtime.getRuntime().exec("ghci"); 

PrintStream hugsin = new PrintStream(p.getOutputStream()); 
InputStream hugsout = p.getInputStream(); 
Scanner rd = new Scanner(System.in); 
new Thread(() -> { 
    try (Reader r = new InputStreamReader(hugsout)) { 
     int ch; 
     while ((ch = r.read()) != -1) 
      System.out.print((char)ch); 
    } catch (IOException e) {} 
}).start(); 
Scanner sc = new Scanner(hugsout); 
String rdnextline; 
while (true) { 
    rdnextline = rd.nextLine(); 
    hugsin.println(rdnextline); 
    hugsin.flush(); 
    if (rdnextline.equals("quit")) { 
     break; 
    } 
} 
System.out.println(" ... successful completion."); 
+0

Danke dafür, es scheint zu funktionieren. Es scheint, du nimmst einen Leser und lässt ihn die Charaktere lesen und sie einzeln ausdrucken. Warum überprüfen Sie, ob der Charakter nicht -1 ist? – dinstruction

+0

'read()' gibt -1 zurück, wenn es geschlossen ist. – saka1029

+0

Und wie kommt die while (true) Schleife nur kontinuierlich Benutzereingaben abgerufen? Es sieht so aus, als ob das Programm die Ausgabe von GHCi nur einmal ausgibt, aber es läuft gut. – dinstruction

Verwandte Themen