How to get regex to get the value after name = in a file, and replace it.
I have a file called: 'myfile.txt'.
public static void main(String[] args)
File TextFile = new File("C:\\text.txt");
if (TextFile.exists()) {
try {
ReplaceWordInFile(TextFile, "haical", "arnanda");
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void ReplaceWordInFile(File MyFile, String OldText, String NewText)
throws IOException {
File tempFile = File.createTempFile("filetemp", ".tmp");
FileWriter fw = new FileWriter(tempFile);
Reader fr = new FileReader(MyFile);
BufferedReader br = new BufferedReader(fr);
while (br.ready()) {
fw.write(br.readLine().replaceAll(OldText, NewText) + "\n");
}
fw.close();
br.close();
fr.close();
tempFile.renameTo(MyFile);
}
Contents of the file C:\text.txt is:
name = haical
address = Michigan 48309, Amerika Serikat
age = 19
gender = male
activity = school
hoby = hiking, travel
If I run the program above in the first line, name = haical will change to name = arnanda.
My problem is that the value from name isn't 'haical' but another value, so I want to get the value after name = blablabla.
Furthermore, sometimes the statement name = haical won't keep it's number of spaces & changes its position.
Example of the contents of the output at a later time is:
address = Michigan 48309, Amerika Serikat
name = haical
age = 19
gender = male
activity = school
hoby = hiking, travel
So it's not always on the first line and some spaces after the = , but it will always be on line starting with name =.
Thanks in advance.
use
....replaceAll("^name\\s*=\\s*" + YourNameVariableToReplace + "\\s*$", "name="+YourNameVariableToInsert)
to replace the string. Maybe you need to escape the Name First, if he might contain Regex-Control-Chars.
Related
I have a csv file that basically mimics a database and my goal is to remove a row from that csv if the csv file contains that username input I provide
the current csv file is:
Jack chan,customer,jack#yorku.ca,jack12,3144134414,13 Arboretum,user2
Donald tusk,customer,donald#yorku.ca,donald1,1213141114,14 Arboretum,user3
tom jack,customer,tom11#yahoo.com,tom44,131344122,14 wells st,user34
jack,parking officer,12rfw#hmail.com,jack,12131131134,12ddcscs,peo1
jewel khan,parking officer,jkhan#hotmail.com,jwel12,2131412141,12 wliis str,peo2
shane li,parking officer,shane#gmail.com,shaneli,1343513414,13 mac st,peo33
james chang,parking officer,james15#gmail.com,james12,31452434114,13 chang st,peo77
my objective is to remove the row of say Shane li using his username "shaneli" and not causing any change to other data. but the current code I have is not causing the file's other data to change
the expected output csv file is row with shaneli gets deleted with other rows remaining intact:
Jack chan,customer,jack#yorku.ca,jack12,3144134414,13 Arboretum,user2
Donald tusk,customer,donald#yorku.ca,donald1,1213141114,14 Arboretum,user3
tom jack,customer,tom11#yahoo.com,tom44,131344122,14 wells st,user34
jack,parking officer,12rfw#hmail.com,jack,12131131134,12ddcscs,peo1
jewel khan,parking officer,jkhan#hotmail.com,jwel12,2131412141,12 wliis str,peo2
james chang,parking officer,james15#gmail.com,james12,31452434114,13 chang st,peo77
this is the code java code I have and I need a java solution:
private static String userPath = "/CSVs/database.csv";
public void removeUser(String name,String userType,String email,String userName,String phoneNumber,String address,String password) {
// FIX THIS
String tmpFile = "tmp.csv";
// String target1 = ""; String target2 = ""; String target3 = ""; String target4 = ""; String target5 = "";String target6 = "";String target7 = "";
String target = "";
File oldFile = new File(userPath);
File newFile = new File(tmpFile);
System.out.println(userName);
try {
FileWriter fw = new FileWriter(tmpFile, true);
BufferedWriter bfw = new BufferedWriter(fw);
PrintWriter pw = new PrintWriter(bfw);
x = new Scanner(new File(userPath));
x.useDelimiter("[,\n]");
while (x.hasNext()) {
target = x.next();
if (!target.equals(userName)) {
pw.printf("%s,%s,%s,%s,%s,%s,%s\n", name, userType,email,userName,phoneNumber,address,password);
// pw.println(target + "," + target + "," + target + "," + target + "," + target + "," + target + "," + target);
}
}
x.close();
pw.flush();
pw.close();
oldFile.delete();
File dmp = new File(userPath);
newFile.renameTo(dmp);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
Please advice
Thanks in advance !!
Solution
The way I've come up with is to do the following:
Create a new file
If the username is not equal, add line, otherwise skip it
Just as we've listed out our steps, we can create a function to do each one.
Code
1) Creating a new file
private void createFile(){
try {
File myObj = new File("CSVs/tmpFile.csv");
} catch (IOException e) {
e.printStackTrace();
}
}
We can then create the file which will be stored at the desired file path and stored as tmpFile.csv.
2) If the username are not equal, add line
private void addDataContents(String userNameToDelete){
try{
String userPath = "CSVs/database.csv";
BufferedReader csvReader = new BufferedReader(new FileReader("CSVs/database.csv"));
String row;
FileWriter myWriter = new FileWriter("CSVs/tmpFile.csv");
while (((row = csvReader.readLine()) != null)){
String[] line = row.split(",");
if (!line[3].equals(userNameToDelete)){
myWriter.write(row + "\n");
}
}
myWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
We then read through the contents of database.csv. We read every line one by one and split the line up by commas as it is a CSV file ( Comma Separated Values ). As the username will always be stored in the 3rd index, we can compare the username we wish to delete with the value stored at the index. If they are not the same, we can go ahead and write the line to our new file. If they are the same, our loop will just continue onto the next line.
Final Notes
I hope everything is easy to read and understandable.
You need to delete the whole row containing specific data from a CSV file. The Java code will be rather long if you try to use the high-level language to do this. It is very simple to accomplish the task in SPL, an open-source Java package. You just need one line of code, as shown below:
A
1
>file("tmp.csv").export#c(file("database.csv").import#wc().select(~(4)!=userNameToDelete))
SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as removeUser.splx and invoke it in Java in the same way you call a stored procedure:
…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st = con.prepareCall("call removeUser(?)");
st.setObject(1,"shaneli");
st.execute();
…
So I am creating a program which when called, will have input, go to a file and change the number assigned to the string called. For example:
The file would look like:
stone 0 wood 5 water 2 metal 5
and if "wood" was called, it would go into the file, find wood then send add one to the value to the right of wood, which would only change that value to 6, then saves the file.
I've looked around on the internet but couldn't really find much which is tailored to my specific problem. Its either changing an int to either one or the other, or changing all ints to something.
public class Main {
public static void main(String[] args) {
FileWriter fw;
BufferedReader reader;
StringBuffer ib;
String allBlockAndNull = "stone 0 wood 5 water 2 metal 5";
String strDir = "C:\\Users\\amdro\\Desktop\\test.txt";
File fileDir = new File(strDir);
//creates file it doesn't exist
try {
fw = new FileWriter(fileDir);
fw.write(allBlockAndNull);
fw.close();
} catch (IOException e) {
e.printStackTrace();
}finally {}
}
}
If you could expand from the above, that would be great!
This is a very simple and basic solution to your problem: It consists of reading the file, appending all changes to a string and overwriting the same file with the string.
Create a scanner to read your text file and initialise a new string variable
Scanner s = new Scanner(new File("fileName.txt"));
String line = "";
While there is still a character in the text file, get the word and the number
while(sc.hasNext()){
String word = s.next();
int number = s.nextInt();
Then, inside the while loop, use switch and case to check the word. For example, if word = "wood", append "wood" and the new number, newNumber to line
case "wood":
line += word + " " + newNumber + " ";
break;
The default will be appending the word and the old number, number
default:
line += word + " " + number + " ";
Finally, just create a FileWriter and a BufferedWriter to write line to the text file.
You can't add numbers to a value from a file because all the values are Strings but what you can do is replace the String value
public static void main(String[] args) throws IOException {
File file = new File("file.txt");//The file containing stone 0 wood 5 water 2 metal 5
BufferedReader reader = new BufferedReader(new FileReader(file));
String words = "", list = "";
while ((words = reader.readLine()) != null) {
list += words;
}
reader.close();
Scanner s = new Scanner(file);
if(list.contains("wood")) {
String replacedtext = list.replaceAll("wood 5", "wood 6");
FileWriter writer = new FileWriter("file.txt");
writer.write(replacedtext);
writer.close();
}
}
}
I have class Account which have username, fullName, password, id and points.
All accounts are saved in a file.I have many accounts in my file, not just one. This is example of one account in text file.
Miljan9602 Rakita Miljan miljan123 1463433398614 0.0
username, full name, password, id and points
Now, for example if i want to change points for my username. First thing i would do is go through all lines in file and compare all usernames, if i find equal username. I would change point's. This is my idea how to do it. Just dont know how to edit it in file.
public void edit(String username, double points)
{
File f = new File("Accounts.txt");
// file doesnt exist, return from method
if(!f.exists())
return;
Scanner sc = null;
try
{
sc = new Scanner(f);
while(sc.hasNextLine())
{
String line = sc.nextLine(); // Take whole line
String split[] = line.split(" "); // Split it so i can check username
if(split[0].equals(username))
{
String change = Double.toString(points); // Make string from double
split[5] = change; // on fifth index are points
/* My question is now how to edit file and to replace my new points
* with old points ?
* Miljan9602 Rakita Miljan miljan123 1463433398614 0.0 <- Need to change this 0.0 with split[4];
*/
}
}
}catch(Exception e)
{
e.printStackTrace();
}finally{
// finally will always close file
sc.close();
}
You could use the Apache's Commons IO library. Everything you'll need, and more, can be found there. Also, here is the GitHub mirror of Commons IO. Worth a look through.
{
File f = new File("Accounts.txt");
FileWriter fw = new FileWriter(f);
// file doesnt exist, return from method
if(!f.exists())
return;
Scanner sc = null;
try
{
sc = new Scanner(f);
while(sc.hasNextLine())
{
String line = sc.nextLine(); // Take whole line
String split[] = line.split(" "); // Split it so i can check username
if(split[0].equals(username))
{
String change = Double.toString(points); // Make string from double
split[5] = change; // on fifth index are points
/* My question is now how to edit file and to replace my new points
* with old points ?
* Miljan9602 Rakita Miljan miljan123 1463433398614 0.0 <- Need to change this 0.0 with split[4];
*/
for(int i = 0; i < spit.length(); i++{
fw.write(split[i] + " ");
}
System.getProperty("line.separator");
}
}
}catch(Exception e)
{
e.printStackTrace();
}finally{
// finally will always close file
sc.close();
fw.close();
}
This should work
As one has to write the entire read text back to the file system, use Files.readAllLines().
Path path = Paths.get(".../Accounts.txt");
Charset charset = StandardCharsets.UTF_8;
List<String> lines = new ArrayList<>();
if (Files.exists()) {
Files.readAllLines(path, charset);
for (int i = 0; i < lines.size(); ++i) {
String split[] = lines.get(i).split(" ");
if (split[0].equals(username)) {
String change = String.valueOf(points);
split[5] = change; // on fifth index are points
StringBuilder sb = new StringBuilder();
for (String value : split) {
if (sb.length() != 0) {
sb.append(' ');
}
sb.append(value);
}
lines.set(i, sb.toString()); // Changes the line.
Files.write(path, lines, charset);
break; // leave loop
}
}
}
More explained
To alter a single line of a text file, one in principle has to load the entire text and after altering the line, safe it entirely.
The reason is that the file can shrink or grow, depending on the line changes.
Even with some twists this is not optimal.
Files.readAllLines is a nice method for that. One might also change the format:
Fixed length records (lines) allow a RandomAccessFile. However a text risks being manually edited so the file gets corrupted, and one also has limited field lengths.
The .properties format allows access with the Properties class. Requirement is a key, and a format key = value. Also the text has some escaping (\).
One could keep Accounts.txt in core, say in a class Accounts, representing all as a Map from user name to Account.
class Account {
public final String userName; // Unmodifiable key
public String password;
...
}
class Accounts {
private Map<String, Account> accountsByUserName = new HashMap<>();
public void loadAccounts() throws IOException { ... }
public void saveAccounts() throws IOException { ... }
public Optional<Account> getAccountByUserName(String userName) { ... }
public void deleteAccountByUserName(String userName) { ... }
public void createAccount(Account account) throws AlreadyExistsException { ... }
}
Forgive me if this is a basic (or not very well explained) question, I am fairly new to Java and have been reading extensive material as well as trying to understand the relevant Javadoc but to no avail.
To give a brief background as to what I am trying to create, I have created a reader class which reads data in from a csv file (4 lines long) including fields such as Item ID, price, description etc. I have created a separate demo class that displays the details of this csv file (through creating an instance of my reader class) and am now trying to create a method that asks the user to input an Item ID that then displays the corresponding Item, based on the ID input by the user. The part I am stuck on is accessing specific rows/columns in a csv file and then comparing these with a given string (entered by the user which corresponds to a specific field in the csv file)
This is what I have come up with thus far:
input = new Scanner(System.in);
System.out.println("Enter a product code");
String prodC = input.next();
//Here I want to know if there is a way of accessing a field in a csv file
Any ideas would be greatly appreciated.
UPDATE
Thank you for quick responses, am currently reading through and seeing how I can try to implement the various techniques. In response to the comment asking about the file reader, this is how I have set that out:
public CatalogueReader(String filename) throws FileNotFoundException {
this.filename = filename;
this.catalogue = new Catalogue();
Scanner csvFile;
try {
csvFile = new Scanner(new File(filename));
} catch (FileNotFoundException fnf) {
throw new FileNotFoundException("File has not been found!");
}
csvFile.useDelimiter("\n");
boolean first = true;
String productCode;
double price;
String description;
double weight;
int rating;
String category;
boolean ageRestriction;
String csvRows;
while (csvFile.hasNextLine()) {
csvRows = csvFile.nextLine();
if (first) {
first = false;
continue;
}
System.out.println(csvRows);
String[] fields = csvRows.split(",");
productCode = (fields[0].trim());
price = Double.parseDouble(fields[1].trim());
description = fields[2].trim();
weight = Double.parseDouble(fields[3].trim());
rating = Integer.parseInt(fields[4].trim());
category = fields[5].trim();
ageRestriction = Boolean.parseBoolean(fields[6].trim());
catalogue.addAProduct(new Item(productCode, price, description, weight, rating, category, ageRestriction));
}
csvFile.close();
}
}
ok so for a CSV file like this:
"1.0.0.0","1.0.0.255","16777216","16777471","AU","Australia"
"1.0.1.0","1.0.3.255","16777472","16778239","CN","China"
"1.0.4.0","1.0.7.255","16778240","16779263","AU","Australia"
"1.0.8.0","1.0.15.255","16779264","16781311","CN","China"
"1.0.16.0","1.0.31.255","16781312","16785407","JP","Japan"
"1.0.32.0","1.0.63.255","16785408","16793599","CN","China"
"1.0.64.0","1.0.127.255","16793600","16809983","JP","Japan"
"1.0.128.0","1.0.255.255","16809984","16842751","TH","Thailand"
here is a sample of how to read using Java Native Libraries
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class CSVReader {
public static void main(String[] args) {
CSVReader obj = new CSVReader();
obj.run();
}
public void run() {
String csvFile = YOURFILEPATHHERE ;
BufferedReader br = null;
String line = "";
String cvsSplitBy = ",";
try {
br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) {
// use comma as separator
String[] country = line.split(cvsSplitBy);
System.out.println("Country [code= " + country[4]
+ " , name=" + country[5] + "]");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("Done");
}
}
does this help?
If you are just doing a single look-up and then exiting then just remember the String you are looking for. As you parse the lines compare to see if you have a match and if you do then return that line.
For repeated searches that would be very inefficient though. Assuming your data set is not too large for memory you would be better off parsing the file and putting it into a Map:
Map<String, Data> dataMap = new HashMap<>();
Parse the file, putting all the lines into the map
Then the lookup just becomes:
Data d = dataMap.get(lineKey);
If d is null then there is no matching line. If it not null then you have found your line.
You can create an array list of object. An object for each line in the CSV. Then search the array object with your search criteria.
User CSVReader framework to read the csv file. Sample code (not exactly what you want)
FileInputStream fis = new FileInputStream(file);
CSVReader reader = new CSVReader(new BufferedReader( new InputStreamReader(fis, "UTF-8" )));
ArrayList<String> row = new ArrayList<String>();
ArrayList<Entry> entries = new ArrayList<Entry>();
// a line = ID, Name, Price, Description
while (!reader.isEOF()) {
reader.readFields(row);
if( row.size() >= 4)
entries.add(new Entry(row.get(0), row.get(1), row.get(2), row.get(3)));
}
System.out.println("Size : "+entries);
i making a program where I would read data from text files and store them in tables in mysql.
In my program the user would give the directory of where the files are, then the program would find only the .txt files and would continue. Afterwards a table would be created and it would have 2 fields and in these fields I would insert the values from the text file.
My issue is that i don't know how! I would explain you what I mean! In my program I would create table with fields (ID, Name). The values of these fields must be taken from the text file. All the files are as the below:
As you can see the ID is in the third row of the file and the Name is in the fifth. Could anyone help me how can I import the values for ID and Name in the table?How can i get only these values each time from the files?
The code for doing the first steps is:
public static void main(String args[]) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection con = (Connection) DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb", "", "");
String dirpath = "";
Scanner scanner1 = new Scanner(System.in);
while (true) {
System.out.println("Please give the directory:");
dirpath = scanner1.nextLine();
File fl = new File(dirpath);
if (fl.canRead())
break;
System.out.println("Error:Directory does not exists");
}
try {
String files;
File folder = new File(dirpath);
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
files = listOfFiles[i].getName();
if (files.endsWith(".txt") || files.endsWith(".TXT")) {
List<File> txtFiles = new ArrayList<File>();
txtFiles.add(listOfFiles[i]);
String[] parts = files.split("\\.");
String tablename = parts[0];
for (File txtFile : txtFiles) {
List sheetData = new ArrayList();
try {
FileReader in = new FileReader(txtFile);
BufferedReader br = new BufferedReader(in);
String line = br.readLine();
while (line != null) {
System.out.println(line);
line = br.readLine();
}
in.close();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
getCreateTable1(con, tablename);
importData(con, txtFile, tablename);
}
}
}
}
} catch (Exception e) {
System.out.println();
}
}
private static String getCreateTable1(Connection con, String tablename) {
try {
Class.forName("com.mysql.jdbc.Driver");
Statement stmt = con.createStatement();
String createtable = "CREATE TABLE "
+ tablename
+ " ( ID INT , name VARCHAR(255)";
System.out.println("Create a new table in the database");
stmt.executeUpdate(createtable);
} catch (Exception e) {
System.out.println(((SQLException) e).getSQLState());
System.out.println(e.getMessage());
e.printStackTrace();
}
return null;
}
BufferedReader br = new BufferedReader(new FileReader(new File("path/to/file")));
String currentLine = br.readLine();
Map<Integer, String> nameByID = new HashMap<Integer, String>();
while (currentLine != null) {
String[] tokens = currentLine.split("\t");
int id = Integer.parseInt(tokens[2]);
String name = tokens[4];
nameByID.put(id, name);
currentLine = br.readLine();
}
br.close();
nameByID will have the names and IDs you need.
Note that some exception handling is required for calls to create a new BufferedReader, for calls to readLine(), and to close the BufferedReader. I didn't insert this because I couldn't remember it off the top of my head but your IDE should prompt you to insert if you're using something like Netbeans or Eclipse
You should try not to reinvent the wheel.
Use a FileNameExtensionFilter to filter the .txt files, this class is from swing but it's fine to use in plain java.
Check if each line matches a regex pattern, that way you can digest the line at the same time as verifying it.
Create a Person object that holds this information and return a Collection of Person - that way you encapsulate your file reading behavior away from your database access layer.
Put all this in a class called, say, FileReader and you have something like the following:
public class FileReader {
private final Pattern linePattern = Pattern.compile("^(\\w++)\\s++(\\w++)\\s*+$");
private final Pattern lineBreakPattern = Pattern.compile("\r?\n");
private final FileFilter txtFilter = new FileNameExtensionFilter("*.txt", "txt");
private final File txtFolder;
public FileReader(File txtFolder) {
this.txtFolder = txtFolder;
}
public List<Person> readFiles() {
final List<Person> people = new LinkedList<>();
for (final File txtFile : txtFolder.listFiles()) {
if (txtFilter.accept(txtFile)) {
people.add(readFile(txtFile));
}
}
return people;
}
private Person readFile(File txtFile) {
try (final Scanner scanner = new Scanner(txtFile)) {
scanner.useDelimiter(lineBreakPattern);
final Person person = new Person();
while (scanner.hasNext()) {
final String line = scanner.next();
final Matcher matcher = linePattern.matcher(line);
if (matcher.matches()) {
switch (matcher.group(1).toUpperCase()) {
case "ID":
person.setId(Integer.parseInt(matcher.group(2)));
break;
case "NAME":
person.setName(matcher.group(2));
break;
default:
throw new IOException("Illegal line '" + matcher.group() + "'.");
}
}
}
return person;
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public static final class Person {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
So you would create a FileReader with the folder that contains the files and then call readFiles, you then save the returned List<Person> in the database.
Lets go through this class.
The readFiles method loops over all files in the directory and checks whether each one of them matches the txtFilter - this filters out any non .txt file.
The readFiles method also creates and returns a List<Person, this is the result of reading the files. The List is populated by the readFile(File txtFile) method. That method is responsible for reading the individual files and parsing them to a Person.
The Person class is a very simple data transfer object, holding on properties and accessors. No logic.
The readFile method creates a Scanner in a Java 7 try-with-resources construct. It sets the delimiter to a platform independent linebreak pattern (\r?\n means that it matches \r\n or \n) and then loops over the scanner output.
Each line is processed with the linePattern, this probably warrants some explanation:
^(\\w++)\\s++(\\w++)\\s*+$
^ is the "start anchor", i.e. the line starts here
(\\w++) means capture any number of word characters
\\s++ means skip any number of whitespace characters
(\\w++) same as above
\\s*+ means skip zero or more whitespace characters
$ is the "end anchor", i.e. the end of the line
So, if the pattern matches we have a valid line. Moreover, when verifying we grabbed to "groups" of characters, these are our key and value.
Next we use a switch on the first group, this is using Java 7 switches with Strings. We populate the person depending on the value of the key, parsing the int where needed.
Finally we return the populated person.
This class should get you well on your way to accomplishing you goal - the sql insertion of the Person objects into a database is trivial.
You may want to add more verification during the file reading process, for example check that both a NAME and ID were found. I leave this as an exercise.