I am trying to read in the data from a text file that is formatted like this:
Operation: ADDITION Attempts: 3
The data I'm trying to read in is the operation and the number of attempts for each line so for example ADDITION and the number 3
This is as far as I could get and I'm still not certain.
File inputFile = new File("mathFile.txt");
Scanner input = new Scanner(inputFile);
while(input.hasNext())
{
String token = input.nextLine();
String[] details = token.split("Operation:");
String operation = details[0];
}
The simplest option is to split on spaces:
String[] parts = token.split(" ");
String operation = parts[1];
String attempts = parts[3];
If you want to get fancier, you can use Regex:
String token = "Operation: ADDITION Attempts: 3";
Matcher matcher = Pattern.compile("^Operation: (\\w+) Attempts: (\\d+)$").matcher(token);
if (matcher.find()) {
String operation = matcher.group(1);
String attempts = matcher.group(2);
}
// Model: line representation
public final class MathFileLine {
private final String operation;
private final int attempts;
public MathFileLine(String operation, int attempts) {
this.operation = operation;
this.attempts = attempts;
}
}
// client code
public static void main(String... args) throws IOException {
List<MathFileLine> lines = readMathFile(Paths.get("mathFile.txt"));
}
#1: Use Stream to read lines with RegEx
public static List<MathFileLine> readMathFile(Path path) throws IOException {
final Pattern pattern = Pattern.compile("^Operation:\\s+(?<operation>\\w+)\\s+Attempts:\\s+(?<attempts>\\d+)$");
return Files.lines(path)
.map(pattern::matcher)
.filter(Matcher::matches)
.map(matcher -> new MathFileLine(matcher.group("operation"), Integer.parseInt(matcher.group("attempts"))))
.collect(Collectors.toList());
}
#2: Use Scanner with custom delimiter to read pairs
public static List<MathFileLine> readMathFile(Path path) throws IOException {
try (Scanner scan = new Scanner(path.toFile())) {
scan.useDelimiter("\\s*(?:Operation:|Attempts:)?\\s+");
List<MathFileLine> lines = new LinkedList<>();
while (scan.hasNext()) {
lines.add(new MathFileLine(scan.next(), scan.nextInt()));
}
return lines;
}
}
There are many ways you can read a text file and split the lines based on some delimiter. In addition to all the other answers here, following is yet another answer that is succinct and self-explanatory.
(1) Read the lines of a file
List<String> lines = Files.lines(Paths.get("mathFile.txt")).collect(Collectors.toList());
(2) Parse what you want from each line
List<String> operations = lines.stream().map(line -> line.split("Operation:")[0]).collect(Collectors.toList());
Related
So i got a Java Class of Konto, which got:
private String navn;
private int medlemdsnummer;
private String årstal;
private String måned;
private String dag;
LocalDate localDate;
They are used like this:
ArrayList<Konto> kontoArrayList = new ArrayList<>();
And I save my ArrayList to a .txt document before the program shutdowns:
private static void saveToFile(ArrayList<Konto> kontoArrayList) throws IOException {
String content = new String(Files.readAllBytes(Paths.get("medlemmer.txt")));
PrintStream printStream = new PrintStream("medlemmer.txt");
for (int i = 0; i < kontoArrayList.size(); i++) {
printStream.println(content + kontoArrayList.get(i).getMedlemdsnummer() + ": " + kontoArrayList.get(i).getNavn() + " " +
kontoArrayList.get(i).getLocalDate());
}
}
They end up looking like this in the .txt file:
1: Kasper 1996-11-20
2: Jonas 1996-04-27
3: Jesper 1996-05-14
Okay, so far so good. Now for the question: When the program is turned on, I want to make it able to load the .txt file from the beginning and "transfer" it to an ArrayList of Konto. So that i later can use my method (addNewMember). I saw a lot of example on the internet, but they all use:
ArrayList<String> somename = new ArrayList<String>();
I want to use:
ArrayList<Konto> konto = new ArrayList<Konto>();
Is this possible, if so how do to?
If not what could i do instead?
Thanks in advance, Victor.
You can read all lines from the file as string and split this strings by spaces.
And then create new objects with parsing of options.
Something like this:
List<String> strings = Files.readAllLines(Paths.get("test.txt"));
List<Konto> kontos = new ArrayList<>();
for (String string : strings) {
String[] data = string.split(" ");
kontos.add(new Konto(data[1], new Date(data[2])));
}
Or using Streams:
List<Konto> kontos = Files.lines(Paths.get("test.txt")) // String
.map(line -> line.split(" ")) // String[]
.map(data -> new Konto(data[1], new Date(data[2])) // Konto
.collect(Collectors.toList());
Something like the following, you've got to check it
class TestParse {
public TestParse(String line) {
StringTokenizer tokenizer = new StringTokenizer(line, ",");
if(tokenizer.countTokens() != 3) {
throw new RuntimeException("error");
}
s1 = tokenizer.nextToken();
s2 = tokenizer.nextToken();
s3 = tokenizer.nextToken();
}
private String s1;
private String s2;
private String s3;
}
public class TestRead {
public static void main(String[] args) throws Exception {
List<TestParse> testParses = new ArrayList<TestParse>();
BufferedReader in = new BufferedReader(new FileReader("file.txt"));
String line;
while((line = in.readLine()) != null) {
testParses.add(new TestParse(line));
}
in.close();
}
}
I think one way you can try is read line by line, and define a Konto constructor that accept a string.
Edit: You can follow the below answer from Lucem. But I think I will do it a little different
List<String> strings = Files.readAllLines(Paths.get("fileName.txt"));
List<Konto> kontos = new ArrayList<>();
for (String s: strings) {
kontos.add (new Konto(s))
}
or using Streams:
List<Konto> kontos = Files.lines(Paths.get("fileName.txt"))
.map(line -> new Konto(line));
.collect(Collectors.toList());
And then in Konto class add a constructor that accept a string and manipulate it. Because you didn't add the class Konto here, I didn't know the exact name of your properties, so I let it be "yourPropertyNumber", "yourPropertyString" and "yourPropertyDate"
class Konto {
public Konto (String input) {
// Split based on white space
String[] dataParts = input.split(" ");
// Get rid of the semicolon
String number = dataParts[0].substring(0, dataParts[0].length - 1);
yourPropertyNumber = parseInt(number);
yourPropertyString = dataParts[1];
yourPropertyDate = new Date(dataParts[2]);
}
// Your other code here
}
The reason I want to pass a String to a constructor rather than parse the string where I read the file is that I think it is easier to debug or make change in the way it reads the string.
Hope this help.
I want to find a special charsequence in a file and I want to read the whole line where the occurrences are.
The following code just checks the first line and fetchess this ( the first ) line.
How can I fix it?
Scanner scanner = new Scanner(file);
String output = "";
output = output + scanner.findInLine(pattern) + scanner.next();
pattern and file are parameters
UPDATED ANSWER according to the comments on this very answer
In fact, what is used is Scanner#findWithHorizon, which in fact calls the Pattern#compile method with a set of flags (Pattern#compile(String, int)).
The result seems to be applying this pattern over and over again in the input text over lines of a file; and this supposes of course that a pattern cannot match multiple lines at once.
Therefore:
public static final String findInFile(final Path file, final String pattern,
final int flags)
throws IOException
{
final StringBuilder sb = new StringBuilder();
final Pattern p = Pattern.compile(pattern, flags);
String line;
Matcher m;
try (
final BufferedReader br = Files.newBufferedReader(path);
) {
while ((line = br.readLine()) != null) {
m = p.matcher(line);
while (m.find())
sb.append(m.group());
}
}
return sb.toString();
}
For completeness I should add that I have developed some time ago a package which allows a text file of arbitrary length to be read as a CharSequence and which can be used to great effect here: https://github.com/fge/largetext. It would work beautifully here since a Matcher matches against a CharSequence, not a String. But this package needs some love.
One example returning a List of matching strings in a file can be:
private static List<String> findLines(final Path path, final String pattern)
throws IOException
{
final Predicate<String> predicate = Pattern.compile(pattern).asPredicate();
try (
final Stream<String> stream = Files.lines(path);
) {
return stream.filter(predicate).collect(Collectors.toList());
}
}
I am trying to convert a text document to shorthand, without using any of the replace() methods in java. One of the strings I am converting is "the" to "&". The problem is, that I do not know the substring of each word that contains the "the" string. So how do I replace that part of a string without using the replace() method?
Ex: "their" would become "&ir", "together" would become "toge&r"
This is what I have started with,
String the = "the";
Scanner wordScanner = new Scanner(word);
if (wordScanner.contains(the)) {
the = "&";
}
I am just not sure how to go about the replacement.
You could try this :
String word = "your string with the";
word = StringUtils.join(word.split("the"),"&");
Scanner wordScanner = new Scanner(word);
I do not get your usage of Scanner for this, but you can read each character into a buffer (StringBuilder) until you read "the" into the buffer. Once you've done that, you can delete the word and then append the word you want to replace with.
public static void main(String[] args) throws Exception {
String data = "their together the them forever";
String wordToReplace = "the";
String wordToReplaceWith = "&";
Scanner wordScanner = new Scanner(data);
// Using this delimiter to get one character at a time from the scanner
wordScanner.useDelimiter("");
StringBuilder buffer = new StringBuilder();
while (wordScanner.hasNext()) {
buffer.append(wordScanner.next());
// Check if the word you want to replace is in the buffer
int wordToReplaceIndex = buffer.indexOf(wordToReplace);
if (wordToReplaceIndex > -1) {
// Delete the word you don't want in the buffer
buffer.delete(wordToReplaceIndex, wordToReplaceIndex + wordToReplace.length());
// Append the word to replace the deleted word with
buffer.append(wordToReplaceWith);
}
}
// Output results
System.out.println(buffer);
}
Results:
&ir toge&r & &m forever
This can be done without a Scanner using just a while loop and StringBuilder
public static void main(String[] args) throws Exception {
String data = "their together the them forever";
StringBuilder buffer = new StringBuilder(data);
String wordToReplace = "the";
String wordToReplaceWith = "&";
int wordToReplaceIndex = -1;
while ((wordToReplaceIndex = buffer.indexOf(wordToReplace)) > -1) {
buffer.delete(wordToReplaceIndex, wordToReplaceIndex + wordToReplace.length());
buffer.insert(wordToReplaceIndex, wordToReplaceWith);
}
System.out.println(buffer);
}
Results:
&ir toge&r & &m forever
You can use Pattern and Matcher Regex:
Pattern pattern = Pattern.compile("the ");
Matcher matcher = pattern.matcher("the cat and their owners");
StringBuffer sb = new StringBuffer();
while(matcher.find()){
matcher.appendReplacement(sb, "& ");
}
matcher.appendTail(sb);
System.out.println(sb.toString());
I am having some problems with this code. I need to write a code where it says SwapField to display columns from a text file and swaps column 2 to be column 1.
public static void main(String[] args) {
int lineNum = 0;
String delimiter = " ";
if (args.length != 3) {
System.out.println("USAGE: java SwapColumn fileName column# column#");
System.exit(-1);
}
String dataFileName = args[0];
String columnAText = args[1];
String columnBText = args[2];
int columnA = Integer.parseInt(columnAText);
int columnB = Integer.parseInt(columnBText);
File dataFile = new File(dataFileName);
Scanner input;
String outputText = null;
System.out.printf("dataFileName=%s, columnA=%d, columnB=%d\n",
dataFileName, columnA, columnB);
try {
input = new Scanner(dataFile);
while (input.hasNextLine()) {
String inputText = input.nextLine();
lineNum++;
outputText = swapFields(inputText, columnA, columnB, delimiter);
System.out.printf("%d: %s\n", lineNum, outputText);
}
} catch (FileNotFoundException FNF) {
System.out.printf("file not found: %s\n", dataFileName);
}
}
static String swapFields(String input, int fieldA, int fieldB, String delim) {
String outputBuffer = "";
//code needed here
return outputBuffer;
}
OK, so you want the method to take in a String input delimited by delim, and swap fields fieldA and fieldB?
static String swapFields(String input, int fieldA, int fieldB, String delim) {
String[] bits = input.split(delim);
String temp = bits[fieldA];
bits[fieldA] = bits[fieldB];
bits[fieldB] = temp;
return String.join(delim, bits);
}
In this code, the .split() method breaks the input up into an array, using delim as the separator (interpreted as a regular expression; see below for the assumptions regarding this). The two relevant (zero-indexed) fields are then swapped, and the String is reconstructed using .join().
Note that the last line (the .join()) requires Java 8. If you don't have Java 8 then you can use StringUtils.join from Apache Commons Lang.
I am also assuming here that your delim is in the right format for the .split() method, which is to say that it's a string literal that doesn't contain escapes and other regex characters. This seems like a plausible enough assumption if it's a delimiter in a text file (usually a comma, space or tab). It further assumes that the delimiter doesn't occur elsewhere in the input, within quotes or something. You haven't mentioned anything about quotes; you'd need to add something to clarify if you wanted to be able to handle such things.
I have the following text file (answers.txt):
Problem A: 23|47|32|20
Problem B: 40|50|30|45
Problem C: 5|8|11|14
Problem D: 20|23|25|30
What I need is something that will read the problem that I tell it(Problem A, Problem B), then read the numbers after it, which are separated by the lines, and print it out like this:
Answers for Problem A: a.23 b.47 c.32 d.20
Does anyone know how this can be done? I've been stuck on it for a while.
Read the lines one by one, split the lines at " " first. The you will get an array with three parts "Problem", "A:" and "23|47|32|20". Then split the third part at "|" so you will get a second array with four parts "23,"47","32","20".
Combine all to get the output you want.
If you want info on how to read lines from a file, or spilt strings then there are billions of tutorials online on how to do that so I wont go into detail on how its done. IM sure you can find them.
Check out this code!
It assumes that you have such file format:
Problem A:
23|7|32|20
Problem B:
40|50|30|45
Problem C:
5|8|11|14
Problem D:
20|23|25|30
because you wrote "numbers after it, which are separated by the lines"
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) throws FileNotFoundException {
Scanner sc = new Scanner(new File("answers.txt"));
List<String> dataList = new ArrayList<String>();
while(sc.hasNextLine()){
dataList.add(sc.nextLine());
}
System.out.println(dataList);
Map<String,String> map = new HashMap<String,String>();
for(int i=0;i<dataList.size();i=i+2){
map.put(dataList.get(i),dataList.get(i+1));
}
for(Entry<String,String> en:map.entrySet()){
System.out.println(en.getKey()+" : "+en.getValue());
}
String problemC = map.get("Problem C:");
String splitted[] = problemC.split("\\|");
System.out.println("Get me problem C: "+String.format("a:%s, b:%s, c:%s, d:%s",splitted[0],splitted[1],splitted[2],splitted[3]));
}
}
Hope this helps!
public static void main(String args[])
{
BufferedReader br = new BufferedReader(new FileReader(new File("answers.txt")));
String lineRead = null;
String problem = "Problem A";//Get this from user Input
List<String> numberData = new ArrayList<String>();
while((lineRead = br.readLine())!=null)
{
if(lineRead.contains(problem))
{
StringTokenizer st = new StringTokenizer(lineRead,":");
String problemPart = st.nextToken();
String numbersPart = st.nextToken();
st = new StringTokenizer(lineRead,"|");
while(st.hasMoreTokens())
{
String number = st.nextToken();
System.out.println("Number is: " + number);
numberData.add(number);
}
break;
}
}
System.out.println("Answers for " + problem + " : " + numberData );
}
Read the lines one by one, split the lines with :. The you will get an array with two parts "Problem A:" and "23|47|32|20". Then split the second part at "|" so you will get a second array with four parts "23,"47","32","20".
Combining all this you will get the output you want.
Cheers!
Use java.util.Scanner and you can filter the integers in the file.
Scanner s = new Scanner (new File ("answers.txt")).useDelimiter("\\s+");
while (s.hasNext()) {
if (s.hasNextInt()) { // check if next token is integer
System.out.print(s.nextInt());
} else {
s.next(); // else read the next token
}
}
Do you know how to read line by line ? If not , chect it How to read a large text file line by line in java?
To sub your string data there have many ways to do. You can sub as you wish. Here for my code..
String data = yourReader.readLine();
String problem = data.substring("Problem".length(), data.indexOf(":"));
System.err.println("Problem is " + problem);
data = data.substring(data.indexOf(":") + 2, data.length());
String[] temp = data.split("\\|");
for (String result : temp) {
System.out.println(result);
}
Assuming there are always four possible answers as in your Example:
// read complete file in fileAsString
String regex = "^(Problem \\w+): (\\d+)\\|(\\d+)\\|(\\d+)\\|(\\d+)$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(fileAsString);
//and so on, read all the Problems using matcher.find() and matcher.group(int) to get the parts
// put in a Map maybe?
// output the one you want...
I might suggest creating a simple data type for the purpose of organization:
public class ProblemAnswer {
private final String problem;
private final String[] answers;
public ProblemAnswer(String problem, String[] answers) {
this.problem = problem;
this.answers = new String[answers.length];
for (int i = 0; i < answers.length; i++) {
this.answers[i] = answers[i];
}
}
public String getProblem() {
return this.problem;
}
public String[] getAnswers() {
return this.answers;
}
public String getA() {
return this.answers[0];
}
public String getB() {
return this.answers[1];
}
public String getC() {
return this.answers[2];
}
public String getD() {
return this.answers[3];
}
}
Then the reading from the text file would look something like this:
public void read() {
Scanner s = new Scanner("answers.txt");
ArrayList<String> lines = new ArrayList<String>();
while (s.hasNext()) {
lines.add(s.nextLine());//first separate by line
}
ProblemAnswer[] answerKey = new ProblemAnswer[lines.size()];
for (int i = 0; i < lines.size(); i++) {
String[] divide = lines.get(i).split(": "); //0 is the problem name, 1 is the list
//of answers
String[] answers = divide[1].split("|"); //an array of the answers to a given
//question
answerKey[i] = new ProblemAnswer(divide[0], answers); //add a new ProblemAnswer
//object to the key
}
}
Now that leaves you with an answer key with ProblemAnswer objects which is easily checked
with a simple .equals() comparison on the getProblem() method, and whatever index is matched, you have all the answers neatly arranged right within that same object.