My Java program needs to launch agrep.exe with parameters for all pairs of elements in a big matrix and get number of matching errors of two stings. I've wrote a code, but it runs very slowly. Can I speed up this part of code? Or, maybe, you can suggest me some java implementation of agrep function?
public static double getSignatureDistance(String one, String two) throws IOException, InterruptedException {
String strReprOne = one.replace(".*","").replace("\\.",".");
String strReprTwo = two.replace(".*","").replace("\\.",".");
PrintWriter writer = new PrintWriter("tmp.txt", "UTF-8");
writer.print(strReprTwo);
writer.close();
List<String> cmd = new ArrayList<>();
cmd.add("agrep.exe");
cmd.add("-B");
cmd.add(one);
cmd.add("tmp.txt");
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
Process proc = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
StringBuilder lineBuilder = new StringBuilder();
String line = "";
char[] buf = new char[2];
while (in.read(buf) == 2) {
lineBuilder.append(buf);
}
line = lineBuilder.toString();
Pattern p = Pattern.compile("(\\d+)\\serror");
Matcher m = p.matcher(line);
double agrep = 0;
if(m.find()) {
agrep = Double.valueOf(m.group(1));
}
in.close();
proc.destroy();
double length = strReprOne.length();
return agrep/length;
}
Can I use FREJ library for this purpose? For example, perform match of strings, get match result and multiply it by length of matched region?
Nobody knows, so I've used FREJ library.
Related
There is such code, I pass two parameters to the input and get the result of this method in the console, I need to save the result in a variable and pass it to another method how to do it right? Please do not rush tomatoes with a beginner in programming, I will be glad to any help. The result of the screen method.
enter image description here
public static String activation(String serialNumber, String keyName) throws IOException, InterruptedException, SQLException {
LocalDate futureDate = LocalDate.now().plusMonths(12);
String formattedDate = futureDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String[] command =
{
"cmd",
};
Process p = Runtime.getRuntime().exec(command);
//new Thread(new SyncPipe(p.getErrorStream(), System.err)).start();
new Thread(new SyncPipe(p.getInputStream(), System.out)).start();
PrintWriter stdin = new PrintWriter(p.getOutputStream());
stdin.println("C:\\tdes_ecb.exe " + serialNumber + " " + keyName + " " + formattedDate);
stdin.close();
int returnCode = p.waitFor();
String code = Integer.toString(returnCode);
return code;
}
static class SyncPipe implements Runnable {
public SyncPipe(InputStream istrm, OutputStream ostrm) {
inputStream = istrm;
outputStream = ostrm;
}
public void run() {
try {
final byte[] buffer = new byte[1024];
for (int length = 0; (length = inputStream.read(buffer)) != -1; ) {
outputStream.write(buffer, 0, length);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < buffer.length; i++) {
char c = (char) buffer[i];
sb.append(c);
}
String convertedString = sb.toString();
key(convertedString);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private final OutputStream outputStream;
private final InputStream inputStream;
}
public void SyncPipe(InputStream inputStream, OutputStream outputStream) {
this.inputStream = inputStream;
this.outputStream = outputStream;
}
For you to get the result of Runtime.getRuntime().exec(command) into a variable, there is no need for a separate thread, you can simple read it right from your object Process and store in a String or StringBuilder, after this it is a matter of understanding the text and splitting it based on your rules.
To immediately read the result of a process:
final StringBuilder ret = new StringBuilder();
final Runtime rt = Runtime.getRuntime();
final String[] commands = { "cmd", "/c", "cd c:\\myuser" };
final Process proc = rt.exec(commands);
final BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
final BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String s = null;
while ((s = stdInput.readLine()) != null) {
ret.append(s).append("\n");
}
while ((s = stdError.readLine()) != null) {
ret.append(s).append("<br />");
}
String res = ret.toString();
After the code above you‘ll have all the text from the results in a String, now it is a matter of splitting it and/or removing unnecessary information. For this you can use the methods indexOf, split and removeAll combined, they are all methods inside the String class.
In you case, to make it simple we can divide the splitting in 3 stages.
1) Ignore the first empty line (\r\n)
2) Ignore the whole first line (command and arguments)
3) Use only the text starting from the position 0 until the next line break
String res = "\r\nC:\\User\\aaa\\bbb\\ccc\\tdex_ecb.exe 000000 111111 33333 44444 \r\n INFO I WANT\r\n C:\\\\User\\\\aaa\\\\bbb\\\\ccc\\\\";
res = res.substring(2);
res = res.substring(res.indexOf("\r\n")+2);
res = res.substring(0, res.indexOf("\r\n"));
System.out.println(res);
Now your variable res has only the text you want to pass to another method.
I am not clear of some parts of your requirement. If it is to get the output of the child process as input in the main Java process, then I don't think it is feasible directly through the Java APIs.
Indirect way of getting child process output in the main Java process
I am not sure if you tried this, but you can redirect the output of the child process into a file and read from that file once the process is over, within the same process. (Of course, if your output data in sensitive, you may not want to do this.)
String filePath = "C:/Temp/abc.txt";
/* Create the process and redirect its output to a new file. */
ProcessBuilder pb = new ProcessBuilder().command( "C:\\Temp\\echo.bat" ) //Replace this with your command
.redirectOutput( Redirect.to( new File( filePath ) ) );
Process p = pb.start();
p.waitFor(); //Now, wait for the process to get over...
/* Now, read from the generated file. */
List<String> lines = Files.readAllLines( Paths.get( filePath ) );
Linking the outputs and inputs, resp., of child and main process
However, if your need is to simply display the output of the child process in the console of the main Java process, you may do this.
Process p = new ProcessBuilder().command( "C:\\Temp\\echo.bat" ) //Replace this with your command
.inheritIO().start();
p.waitFor();
I wanted to run a script from java class.
I was able to do it with ProcessBuilder.
Now I am struggling to pass data as an argument to the script. I can pass a string, but I am having trouble passing list of data (data read from a CSV file).
One that I tried was using StringBuffer and passing the data as Bytes
StringBuffer sb = new StringBuffer();
ArrayList argsList = new ArrayList();
// append the sb from record.
//convert it to bytes
//sb.toString() contains my data with a delimiter ';'
// sb.toString().getBytes("UTF-8").toString()
argsList.add(0,"Continuum/anaconda3/envs/sth/python");
argsList.add(1,"python/test.py");
argsList.add(2,"python/test.py");
argsList.add(3,sb.toString().getBytes("UTF-8").toString())
ProcessBuilder builder = new ProcessBuilder(argsList);
Process p = builder.start();
I can not pass sb.toString().getBytes("UTF-8") to the process builder.
I get java.lang.ArrayStoreException
On the other hand, if I pass sb.toString(), I get
java.io.IOException: Cannot run program Continuum/anaconda3/envs/sth/python, CreateProcess error=206, The filename or extension is too long
add it to list of commands to process builder.
How can I read what I passed in python?
Is this even the right way to pass data ( row X column)?
Thanks
You can try below code ::
import java.io.*;
class RunPythonCommand {
public static void main(String [] args) {
try {
String prg = "import sys\nprint int(sys.argv[1])+int(sys.argv[2])\n";
BufferedWriter out = new BufferedWriter(new FileWriter("sample_code.py"));
out.write(prg);
out.close();
int param1 = 10;
int param2 = 32;
ProcessBuilder pb = new ProcessBuilder("python", "sample_code.py", "" + param2, "" + param1);
Process p = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
int ret = new Integer(in.readLine()).intValue();
System.out.println("value is : " + ret);
} catch (Exception e) {
System.out.println(e);
}
}
}
Hope it will help you
You can pass args as array.:
final String PYTHON = "python";
final String SCRIPT_PATH = new File("Pyscript.py").getPath();
final String ACTION = "-aexport";
final String[] CMD_ARRAY = {PYTHON, SCRIPT_PATH, ACTION};
ProcessBuilder processBuilder = new ProcessBuilder(CMD_ARRAY);
I want to read the stdout of a process right as it is generated.
The process will send information for a progress indicator, so it doesn't make sense that I get the information all at once, which I do and which is the problem. I tried to use Scanner class as suggested in a post, but I still get the output only after the process has finished.
I realize this question has been asked before, but it hasn't been answered.
You will probably want to look at class StreamGobblerOutput first.
public List<String> executeCall(String fileName)
{
StringBuilder sbOutput = new StringBuilder();
StringBuilder sbError = new StringBuilder();
File file = new File(fileName);
try ( BufferedReader br = new BufferedReader(new FileReader(file)) ) {
String line;
while ((line = br.readLine()) != null) {
String [] parts = line.split("\\s");
if(parts.length<2) {
sbError.append("Command too short for call: " + parts[0]);
continue;
}
List<String> args = new ArrayList<String>();
args.add ("sfb.exe");
for(int i = 1; i <parts.length; ++i) {
args.add (parts[i]);
}
args.add (sfbPassword);
ProcessBuilder pb = new ProcessBuilder (args);
pb.directory(new File(Support.getJustThePathFromFile(file)));
Map<String, String> envs = pb.environment();
String path = envs.get("Path");
envs.put("Path", Paths.get(".").toAbsolutePath().normalize().toString() + ";" +path);
//pb.redirectOutput(new Redirect() {});
Process p = pb.start();
String outputPathPrefix = pb.directory().getCanonicalPath();
// any output?
StreamGobblerOutput outputGobbler = new StreamGobblerOutput(p.getInputStream(), outputPathPrefix);
outputGobbler.start();
// any errors?
StreamGobblerError errorGobbler = new StreamGobblerError(p.getErrorStream());
errorGobbler.start();
try
{
p.waitFor();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
sbOutput = outputGobbler.getOutput();
sbError = errorGobbler.getErrors();
String rootPath= Support.getJustThePathFromFile(new File(fileName));
File rootFile = new File(rootPath + "/..");
String rootFolder = rootFile.getCanonicalFile().getName();
System.err.println("rootFolder: " + rootFolder);
mainApp.addModifiedFiles(outputGobbler.getModifiedFileNames(), rootFolder);
}
} catch ( IOException ex) {
sbError.append(ex.getMessage());
}
mainApp.addOutput(sbOutput.toString());
mainApp.addError(sbError.toString());
return;
}
private class StreamGobblerOutput extends Thread {
private InputStream is;
private String outputPathPrefix;
private StringBuilder sbOutput;
private List<String> modifiedFileNames;
private Scanner scanner;
private StreamGobblerOutput(InputStream is, String outputPathPrefix) {
this.is = is;
this.outputPathPrefix = outputPathPrefix;
sbOutput = new StringBuilder();
modifiedFileNames = new ArrayList<String>();
scanner = new Scanner(is);
}
public StringBuilder getOutput() {
return sbOutput;
}
public List<String> getModifiedFileNames() {
return modifiedFileNames;
}
#Override
public void run() {
//create pattern
Pattern patternProgress = Pattern.compile("\\((\\d+)%\\)");
//InputStreamReader isr = new InputStreamReader(is);
//BufferedReader br = new BufferedReader(isr);
String ligne = null;
while (scanner.hasNextLine()) {
ligne = scanner.nextLine();
sbOutput.append(ligne);
sbOutput.append("\r\n");
//bw.write("\r\n");
Matcher mProgress = patternProgress.matcher(ligne);
if (mProgress.find()) {
int percentage = Integer.parseInt(mProgress.group(1));
System.err.println("percentage=" + percentage);
mainApp.mainWindowController.setProgressExecute(percentage/100.0);
}
}
mainApp.mainWindowController.setProgressExecute(1.0);
if (scanner != null) {
scanner.close();
}
}
}
private class StreamGobblerError extends Thread {
private InputStream is;
private StringBuilder sbError;
private Scanner scanner;
private StreamGobblerError(InputStream is) {
this.is = is;
sbError = new StringBuilder();
scanner = new Scanner(is);
}
public StringBuilder getErrors() {
return sbError;
}
#Override
public void run() {
//InputStreamReader isr = new InputStreamReader(is);
//BufferedReader br = new BufferedReader(isr);
String ligne = null;
while (scanner.hasNextLine()) {
ligne = scanner.nextLine();
sbError.append(ligne);
sbError.append("\r\n");
}
if (scanner != null) {
scanner.close();
}
}
}
Update: I tried redirecting the output to a file and reading from it, but it appears this runs into the same buffering problem as the previous implementation: I get only two data points.
As a workaround, I will have to ask the creator of the .exe to include 4100 extra characters in each line showing the progress.
If your external process is C/C++ (stdio) based, than this is most likely a block buffering issue:
stdio-based programs as a rule are line buffered if they are running interactively in a terminal and block buffered when their stdout is redirected to a pipe. In the latter case, you won't see new lines until the buffer overflows or flushed.
see this answer for more details, and some possible workarounds.
Please also note that according to this, line buffering is not an option on Win32:
_IOLBF
For some systems, this provides line buffering. However, for Win32, the behavior is the same as _IOFBF - Full Buffering.
so if you choose to modify the "exe" program to set a proper output mode with setvbuf, you would have to use:
_IONBF No buffer
instead.
From the Javadocs
Optionally, a PrintStream can be created so as to flush automatically;
this means that the flush method is automatically invoked after a byte
array is written, one of the println methods is invoked, or a newline
character or byte ('\n') is written.
Reference: http://docs.oracle.com/javase/8/docs/api/java/io/PrintStream.html
One way to do this is to have output stream flush() after every write.
System.out.flush()
You could also define your own flushable PrintStream and use that.
I have following code:
private String ReadCPUinfo()
{
ProcessBuilder cmd;
String result="";
try{
String[] args = {"/system/bin/cat", "/proc/cpuinfo"};
cmd = new ProcessBuilder(args);
Process process = cmd.start();
InputStream in = process.getInputStream();
byte[] re = new byte[1024];
while(in.read(re) != -1){
System.out.println(new String(re));
result = result + new String(re);
}
in.close();
} catch(IOException ex){
ex.printStackTrace();
}
return result;
}
and String from /proc/cpuinfo as result. I need to extract processor info (Processor: WordIWantToExtract) as String to put it in the TextView.
I did it in Python script (print cpuinfo to the txt file, then lookup line number with word "Processor", return its line number and then printing this line with editing). How can I port this to the Java?
/proc/cpuinfo is just a text file. Just use a BufferedReader and read the contents instead of using ProcessBuilder. Check for the the prefix "Processor" to extract the exact line.
BufferedReader reader =
Files.newBufferedReader(Paths.get("/proc/cpuinfo"), StandardCharsets.UTF_8);
while ((line = reader.readLine()) != null) {
Matcher m = Pattern.compile("Processor: (.*)").matcher(line);
if (m.find()) {
System.out.println("Processor is " + m.group(1));
...
}
}
I would use a JSONObject. Yo ucan create the object with a "key" processor and the word you want. For example,
Map<String, String> processors = new HashMap<String, String>();
loggingMap.put("Processor", "Word");
JSONObject jsonObject = new JSONObject();
jsonObject.element(processors);
The line will look like this, {"Processor": "word", "Other Key": "Other Word"}
Then you can write this to a file,
jsonObject.write(Writer writer);
Then you can read the line from the file and use,
jsonObject.getString("Processor");
I used a HashMap incase you have keys and values.
I'm not sure to understand well your question but I think you can add this after the while loop:
Matcher matcher = Pattern.compile("Processor: (.*)").matcher(result);
if (matcher.find()) {
String wordYouWantToExtract = matcher.group(1);
}
I want to put in a file some regex expressions and separated by a semicolon (or something) another expression, i.e.:
orderNumber:* completionStatus;orderNumber:X completionStatus
I will have a log file what will have:
.... orderNumber:123 completionStatus...
and I want them to look like:
.... orderNumber:X completionStatus...
How can I do this in Java?
I've tried creating a Map with (key: the regex, and value: the replacement), reading my log file and for each line try matching the keys but my output looks the same.
FileInputStream fstream = new FileInputStream(file);
// Get the object of DataInputStream
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader( in ));
FileWriter fstreamError = new FileWriter(myFile.replace(".", "Replaced."));
BufferedWriter output = new BufferedWriter(fstreamError);
while ((strFile = br.readLine()) != null) {
for (String clave: expressions.keySet()) {
Pattern p = Pattern.compile(clave);
Matcher m = p.matcher(strFile); // get a matcher object
strFile = m.replaceAll(expressions.get(clave));
System.out.println(strFile);
}
}
Any thoughts on this?
It seems like you are on a good path. I would however suggest several things:
Do not compile the regex every time. You should have them all precomplied and just produce new matchers from them in your loop.
You aren't really using the map as a map, but as a collection of pairs. You could easily make a small class RegexReplacement and then just have a List<RegexReplacement> that you iterate over in the loop.
class RegexReplacement {
final Pattern regex;
final String replacement;
RegexReplacement(String regex, String replacement) {
this.regex = Pattern.compile(regex);
this.replacement = replacement;
}
String replace(String in) { return regex.matcher(in).replaceAll(replacement); }
}
is this what you are looking for?
import java.text.MessageFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexpTests {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String text = "orderNumber:123 completionStatus";
String regexp = "(.*):\\d+ (.*)";
String msgFormat = "{0}:X {1}";
Pattern p = Pattern.compile(regexp);
Matcher m = p.matcher(text);
MessageFormat mf = new MessageFormat(msgFormat);
if (m.find()) {
String[] captures = new String[m.groupCount()];
for (int i = 0; i < m.groupCount(); i++) {
captures[i] = m.group(i + 1);
}
System.out.println(mf.format(msgFormat, captures));
}
}
}