replace a string segment from input stream - java

I am trying to receive a huge text file as an inputstream and want to convert a string segment with another string. I am strictly confused how to do it, it works well if I convert whole inputstream as a string which I don't want as some of the contents are lost. can anyone please help how to do it??
e.g.
if I have a file which has the contents "This is the test string which needs to be modified". I want to accept this string as input stream and want to modify the contents to "This is the test string which is modified" , ( by replacing 'needs to be' with is).
public static void main(String[] args) {
String string = "This is the test string which needs to be modified";
InputStream inpstr = new ByteArrayInputStream(string.getBytes());
//Code to do
}
In this I want the output as: This is the test string which is modified
Thanking you in advance.

If the text to be changed will always fit in one logical line, as I stated in comment, I'd go with simple Line Reading (if applyable) using something like:
public class InputReader {
public static void main(String[] args) throws IOException
{
String string = "This is the test string which needs to be modified";
InputStream inpstr = new ByteArrayInputStream(string.getBytes());
BufferedReader rdr = new BufferedReader(new InputStreamReader(inpstr));
String buf = null;
while ((buf = rdr.readLine()) != null) {
// Apply regex on buf
// build output
}
}
}
However I've always like to use inheritance so I'd define this somewhere:
class MyReader extends BufferedReader {
public MyReader(Reader in)
{
super(in);
}
#Override
public String readLine() throws IOException {
String lBuf = super.readLine();
// Perform matching & subst on read string
return lBuf;
}
}
And use MyReader in place of standard BufferedReader keeping the substitution hidden inside the readLine method.
Pros: substitution logic is in a specified Reader, code is pretty standard.
Cons: it hides the substitution logic to the caller (sometimes this is also a pro, still it depends on usage case)
HTH

May be I understood you wrong, but I think you should build a stack machine. I mean you can use a small string stack to collect text and check condition of replacement.
If just collected stack already is not matched to your condition, just flush stack to output and collect it again.
If your stack is similar with condition, carry on collecting it.
If your stack is matched your condition, make a modification and flush modified stack to output.

Related

Handling Errors with try and catch blocks

I Have a question abouth the code for handling erros made by the user.
So the thing is, I need my user to add a name of a program, to add the memory that program takes in the RAM and to add the time he will have that program open.
I need to add in my code defensive programming, so I thought maybe I could do it by checking if the user actually add the type of the variables that the program need, or if it didn't.
Either way I am confused on how to use the try and catch blocks, for now this is what I have...
System.out.println("add program Id");
String programID = scan.next();
try{
String check;
check = programID;
}catch(Exception e){
System.out.println("add a value of String type");
}
That doesn't work.
anything you can type is a string. I can type '5'. That's a string. You may think it is a number, but this entire block of text is a String, and '5' is in it.
No text is a string too. String x = ""; compiles fine.
Thus, no exception would ever occur here, and it's not clear what scenario you are trying to detect.
Perhaps a programID is of the form: "one capital letter (and only english capitals, not Ü for example), and then up to 3 different digits". For example, 'Z5' or 'Y495'.
You'd need to write code to detect this, no need for try/catch. For example, regular expressions:
private static final Pattern PROGRAM_ID_PATTERN = Pattern.compile("^[A-Z]\\d{1,3}$");
public static void main(String[] args) {
....
String programId;
do {
programId = scanner.next();
if (!PROGRAM_ID_PATTERN.matcher(programId).matches()) {
System.err.println("Enter a valid program ID, e.g. A123");
} else {
break;
}
} while (true);
}
Exceptions are for when a method has multiple different ways to exit.
For example, imagine this method:
byte[] contentsOfFile = Files.readFileFully("myfile.txt");
The readFileFully method seems simple: You provide the name of a file, and it returns a byte array with its contents.
However, that's just one way that could go. What if the file doesn't exist? What if the file exists, but your process doesn't have read access rights? What if the disk is failing or it's a removable drive and it's yanked out halfway through reading it?
These somewhat predictable potential alternate ways out are generally done by exceptions. That method would be throwing FileNotFoundException, noReadAccessException, and more generally IOException, for example.
There's no 'that is not a string' variant of scanner.next().
There is scanner.next(Pattern) which you could use:
private static final Pattern PROGRAM_ID_PATTERN = Pattern.compile("^[A-Z]\\d{1,3}$");
public static void main(String[] args) {
....
String programId;
do {
try {
programId = scanner.next(PROGRAM_ID_PATTERN);
break;
} catch (NoSuchElementException e) {
System.err.println("Enter a valid program ID, e.g. A123");
}
} while (true);
}
The javadoc generally explains what exceptions can occur; if a method doesn't mention any, you're not supposed to try/catch there.

Save huge amount of Strings in file during program execution in Java

In my program the main logic is to construct Strings in different methods and then to save them in a specific order in a file. But my memory consumption is very high, so I wonder how to save less strings in memory. So I will try to simplify the program for the ease of reading here. My small String Generating methods do like:
Then my main logic is something like:
BufferedWriter bw = new BufferedWriter(fw);
for(int i=1;i<1_000_000_000;i++){
bw.write(processMethod(i));
}
bw.close();
where the processMethod is a method that calls methods like generateTag m times, makes String using StringBuilder and then saves to BufferedWriter .
public static String generateTag(final String tagName, final String name, final String value) {
StringBuilder attribute = new StringBuilder();
attribute.append("<tag:");
attribute.append(tagName);
attribute.append(" name=\"");
attribute.append(name);
attribute.append("\">");
attribute.append(value);
attribute.append("</tag:");
attribute.append(tagName);
attribute.append(">");
return attribute.toString();
}
So when I start the processMethod executes 1_000_000_000 times and then m times is called generateTag like methods. I have 1_000_000_000 * m strings in the memory. How can I easily remove their creation? I think something like:
public static String generateTag(final String tagName, final String name, final String value, final BufferedWriter bf) {
....
bf.write(someBuilder.toString());
..
}
But passing BufferedWriter around is not a good I think.
Can you suggest me some less String created description.
If indeed your program merely calls methods one after the other and those methods generate strings and those strings are written to the file in the order they are generated, then it's simpler to write directly to the file using the main BufferedWriter:
try (BufferedWriter bw = new BufferedWriter(fw);) {
for(int i=1;i<1_000_000_000;i++){
processMethod(i, bw);
}
}
(Note that I used try-with-resources to automatically close the buffered writer).
And then when processMethod calls generateTag, it passes the buffered writer to it:
public void processMethod(int i, BufferedWriter bw) {
...
generateTag(...,bw);
...
}
And generateTag is going to be:
public static void generateTag(final String tagName, final String name, final String value, final BufferedWriter bw) {
bw.write("<tag:");
bw.write(tagName);
bw.write(" name=\"");
bw.write(name);
bw.write("\">");
bw.write(value);
bw.write("</tag:");
bw.write(tagName);
bw.write(">");
}
Since BufferedWriter is buffered, it means that there is disk access not every time you call write, but every time the buffer is filled up. So this won't cost you in disk access speed. But it will save you all that memory.
Of course, if you don't write the results serially, or the result of one method depends on the result of the other, then you need to modify this, but still, you should write as soon as you have the next piece of String ready.
One thing you may consider is to not saving them in memory, and instead write them as soon as possible...
many XML api like jdom, dom and dom4j abet the harmful habits of building tree model in memory, whereas in reality, it is far more efficient to dump the byte out into output buffer asap...
You could rewrite your method to include an output stream variable and flush out all the bytes out with the output stream.
Use the Appendable abstraction to ensure the generateTag (and likewise processMethod, if you wish) have no dependency to BufferedWriter. In fact, we can even pass a StringBuilder to do the same as before, a feature, which we can use to provide an appropriate overload:
public static CharSequence generateTag(
final String tagName, final String name, final String value) {
StringBuilder attribute=new StringBuilder(80);
try { generateTag(tagName, name, value, attribute); }
catch (IOException ex) { throw new AssertionError(ex); }
return attribute;
}
public static void generateTag(
final String tagName, final String name, final String value, Appendable attribute)
throws IOException {
attribute.append("<tag:");
attribute.append(tagName);
attribute.append(" name=\"");
attribute.append(name);
attribute.append("\">");
attribute.append(value);
attribute.append("</tag:");
attribute.append(tagName);
attribute.append(">");
}
Note that the overload returns CharSequence rather than String to be able to omit the final StringBuilder.toString() copying step. Unfortunately, calling append(CharSequence)on the BufferedWriter with it would not pay off, given the current implementation. Still there are APIs allowing to use CharSequence directly.

Java stringbuffer method

I am learning Java in this summer st college in US. I am new to Stringmethod.
I try to understand how to use Stringbuffer() method.
I tried to make ssl=statusBuffer in Else if section, but it causes error; how should I fix appropriate way?
Thank you so much.
public class test {
public static void main(String[] args){
String s= "123-45-6789";
String ssl;
int slength = (s.length());
if(slength ==11)
{
ssl = s;
}
else if(slength =9){
StringBuffer statusBuffer = new StringBuffer(s);
statusBuffer.insert(3,"-");
statusBuffer.insert(6,"-");
ssl=statusBuffer; //------ This part is causing error**
}
System.out.println(ssl);
}
}
ssl is a String. statusBuffer is a StringBuffer.
You need
ssl = statusBuffer.toString();
StringBuffer is not a string. You have to call statusBuffer.toString() to actually get the String from your StringBuffer.
In Java, Strings cannot be modified. If you create a String, it is always that String. If you modify a String, a new string is created. A StringBuffer is basically a modifiable String, which can be used for performance reasons when assembling big texts. They are also Thread safe. For more information, see the javadocs

Using BufferedReader

I am doing a method involving BufferedReader and I to have use it as an input argument, can someone tell me how to use it as an input argument but initialize it outside the method?
Other thing is, how do I get the buffer to read special characterS? (eg: ´, ~)
public static List<Pacote<Pair<String, Double>>> create(
BufferedReader fileReader, int capacidadePacotes)
throws IOException {
List retorno = new ArrayList <> (6);
String s;
while ((s=fileReader.readLine())!=null){
retorno.add(parseItem(s));
}
return retorno;
}
It basically reads a file and sends it to another function that treats the text and creates objects based on that, I'm just not clear on the whole using BufferedReader as an input argument, have just used it inside the method before so I'm unclear on how to initialize it properly, probably a dumb question but I would like to know how to do it properly
You can initialize the BufferedReader object as follows if you are trying to read a file.
public static void main(String[]args) {
BufferedReader rdr = new BufferedReader(new FileReader("filepath"));
int capacidadePacotes = 10;
create(rdr, capacidadePacotes);
}
//urcode for create
The buffered reader can read line by line using the readLine() method. If you read null that means you reached the end of the file. A more readable way to use the buffered reader would be the following:
String s = rdr.readLine();
while(s != null) { //while u didn't reach the end of the file
//your code
s = rdr.readLine();
}
If you want to initialize it "outside" the method, why not hand it over like that:
create(new BufferedReader(reader, 3));
Or how exactly do you want it to have instantiated? For the instantiation, you need a Reader, which can be handed over. If you want to create a Reader from a file, the answer is also in the following link.
How to read special characters with a BufferedReader:
Read special characters in java with BufferedReader

Compare files string by string

I have two files:
Grader.getFileInfo("data\\studentSubmissionA.txt");
Grader.teacherFiles("data\\TeacherListA.txt");
Both contain a list of math problems, but the TeacherList is unsolved in order to check that the StudentSubmission was not altered from the original version.
studentSubmission is sent to the Grader class and the method currently looks like this:
public static void getFileInfo(String fileName)
throws FileNotFoundException {
Scanner in = new Scanner(new File(fileName))
while (in.hasNext()) {
String fileContent = in.nextLine();
}
and the TeacherFiles method looks like
public static void teacherFiles(String teacherFiles)
throws FileNotFoundException{
Scanner in = new Scanner(new File(teacherFiles));
while (in.hasNext()){
String teacherContent = in.nextLine();
String line = teacherContent.substring(0, teacherContent.indexOf('='));
}
I don't know how to get these methods to another method in order to compare them since they're coming from a file and I have to put something in the method signature to pass them and it doesn't work.
I tried putting them in one method, but that was a bust as well.
I don't know where to go from here.
And unfortunately, I can't use try/catches or arrays.
Is it possible to send the .substring(0 , .indexof('=')) through the methods?
Like line = teacherFiles(teacherContent.substring(0 , .indexof('='))); Is it possible to do this?
Think in more general terms. Observe that your methods called getFileInfo and teacherFiles, respectively are the very same except a few nuances. So why do not we think about finding the optimal way of merging the two functionalities and handling the nuances outside of them?
It is logical that you cannot use arrays as you need to know the number of elements of your array before you initialize it and your array would have already been initialized when you read the file. So using an array for this task is either an overkill (for example you allocate 1000 elements in your memory and you use only 10 elements) or insufficient (if you create an array of 10 elements, but you would need 1000). So, due to the fact that you do not know the number of rows in advance you need to use another data structure for your task.
So create the following method:
public static AbstractList<String> readFile(String filePath) throws FileNotFoundException, IOException {
Scanner s = new Scanner(new File(filePath));
AbstractList<String> list = new ArrayList<String>();
while (s.hasNext()){
list.add(s.next());
}
s.close();
return list;
}
Then use the method to read the student file and to read the teacher file. Store the results into two separate AbstractList<String> variables, then iterate through them and compare them as you like. Again, think in more general terms.

Categories