I have string like this "7.51B, 8.01B, 7.02E, 7.52E, 8.02E,
7.01D, 7.51D, 8.01D, 8.54E, 9.04E, 9.54E, 10.04E, 10.54E, 11.04E" . I would like to group this string based on 1B , 2E , 1D , 4E using regex . Any help ?
Example:
Input
String s1 = "7.51B, 8.01B, 7.02E, 7.52E, 8.02E, 7.01D, 7.51D, 8.01D, 8.54E, 9.04E, 9.54E, 10.04E, 10.54E, 11.04E"
output:
1B - 7.51B, 8.01B
2E - 7.02E, 7.52E, 8.02E
1D - 7.01D, 7.51D, 8.01D
4E - 8.54E, 9.04E, 9.54E, 10.04E, 10.54E, 11.04E
Like already mentioned in the coments above the easiest way is to split and filter by ending. Example:
public static void main(String[] args){
String s = "7.51B, 8.01B, 7.02E, 7.52E, 8.02E, 7.01D, 7.51D, 8.01D, 8.54E, 9.04E, 9.54E, 10.04E, 10.54E, 11.04E";
String[] keys = {"1B","2E","1D","4E"};
Map<String, List<String>> map = new TreeMap<>();
for(String k :keys){
map.put(k, Arrays.stream(s.split(",")).filter(e->e.endsWith(k)).collect(Collectors.toList()));
}
System.out.println(map);
}
Related
I'm getting the following errors and having troubles with fixing it. Any help is appreciated! Before anyone jumps saying that my code needs to look "cleaner" please know I'm brand new to this and still learning.
When running my Game.java it's giving me this...
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.base/java.util.Scanner.nextLine(Scanner.java:1651)
at ItemGenerator.textFileReaderSpecialItems(ItemGenerator.java:71)
at ItemGenerator.<init>(ItemGenerator.java:22)
at Game.<init>(Game.java:9)
at Game.main(Game.java:16)
This is the code around these lines
ItemGenerator.java
58 public void textFileReaderSpecialItems(String x) {
59
60 try {
61
62 Scanner fileSc = new Scanner(new File(x));
63
64 while(fileSc.hasNext() && fileSc != null) {
65
66 String s1;
67 String s2;
68 String s3;
69
70 s1 = fileSc.nextLine();
71 s2 = fileSc.nextLine();
72 s3 = fileSc.nextLine();
73
74 itemsList.add(new Items(s1, s2, s3));
75 }
76
77 fileSc.close();
78
79 } catch (FileNotFoundException e) {
80
81 System.out.println("\nError: " + e + "\nProgram exiting...\n");
82 System.exit(0);
83
84 }
85
87 }
3 public Game() {
4
5 LocationGenerator newLocationGenerator = new LocationGenerator("Locations.txt");
6 MainCharacterGenerator newMainCharacter = new MainCharacterGenerator("MainCharacter.txt");
7 CharacterGenerator newCharacter = new CharacterGenerator("Characters.txt", "Jabberwocky.txt");
8 ItemGenerator newItem = new ItemGenerator("Items.txt", "SpecialItems.txt");
9 newLocationGenerator.startLocation();
10
11 }
12
13 public static void main(String[] args) {
14
15 Game game = new Game();
16
17 }
Any help would be appreciated! Learning curve for me!
Labeled all my information
The following will ensure your list is filled when the input file is valid:
public void textFileReaderSpecialItems(String x) {
try {
Scanner fileSc = new Scanner(new File(x));
int lineCount = 0;
List<String> lineBuffer = new ArrayList<>();
while (fileSc.hasNextLine()) {
lineBuffer.add(fileSc.nextLine());
lineCount++;
if (lineBuffer.size() % 3 == 0) {
itemsList.add(new Items(lineBuffer.get(0), lineBuffer.get(1), lineBuffer.get(2)));
lineBuffer.clear();
}
}
System.out.println(itemsList);
fileSc.close();
} catch (FileNotFoundException e) {
System.err.println("\nError: " + e + "\nProgram exiting...\n");
System.exit(1);
}
}
Note that method names should be verb-based, not noun-based. So, something like fillSpecialItems. Also, only return an exit code of zero on success. Use System.err for errors. Later, you will use System.err.printf maybe. Note the format character for a line separator is "%n". What you used ("\n") is OS-specific. Really, if you're not using logging (which you should in real-world, professional apps) you should always use e.printStackTrace() for exceptions - you want the maximum info possible.
I'm currently trying to read in coordinates from a TSP-file, they usually look something like this:
NAME: berlin52
TYPE: TSP
COMMENT: 52 locations in Berlin (Groetschel)
DIMENSION: 52
EDGE_WEIGHT_TYPE: EUC_2D
NODE_COORD_SECTION
1 565.0 575.0
2 25.0 185.0
3 345.0 750.0
4 945.0 685.0
5 845.0 655.0
6 880.0 660.0
7 25.0 230.0
8 525.0 1000.0
9 580.0 1175.0
10 650.0 1130.0
11 1605.0 620.0
12 1220.0 580.0
13 1465.0 200.0
14 1530.0 5.0
15 845.0 680.0
16 725.0 370.0
17 145.0 665.0
18 415.0 635.0
19 510.0 875.0
20 560.0 365.0
21 300.0 465.0
22 520.0 585.0
23 480.0 415.0
24 835.0 625.0
25 975.0 580.0
26 1215.0 245.0
27 1320.0 315.0
28 1250.0 400.0
29 660.0 180.0
30 410.0 250.0
31 420.0 555.0
32 575.0 665.0
33 1150.0 1160.0
34 700.0 580.0
35 685.0 595.0
36 685.0 610.0
37 770.0 610.0
38 795.0 645.0
39 720.0 635.0
40 760.0 650.0
41 475.0 960.0
42 95.0 260.0
43 875.0 920.0
44 700.0 500.0
45 555.0 815.0
46 830.0 485.0
47 1170.0 65.0
48 830.0 610.0
49 605.0 625.0
50 595.0 360.0
51 1340.0 725.0
52 1740.0 245.0
EOF
What I want to do is to read all the nodes, their two coordinates and create a node from this. I would like to store them in an arraylist storing lists, like:
ArrayList<String[]>
My code is currently looking like this:
package group12.TSP.tree;
import java.io.File;
import java.util.*;
public class Tree {
ArrayList<String[]> storing = new ArrayList<String[]>();
public Tree() throws Exception{
File file = new File("C:/Users/joaki/Desktop/burma14.tsp");
Scanner sc = new Scanner(file);
storing = new ArrayList<String[]>();
String nextValue = null;
//sc.reset();
sc.useDelimiter(" ");
while (sc.hasNextLine()) {
sc.nextLine();
while(sc.hasNextDouble()) {
nextValue = sc.nextLine();
//st.replaceAll("\\s+","")
//nextValue = nextValue.replace(" ", "");
storing.add(nextValue.split(""));
continue;
}
}
sc.close();
}
public static ArrayList<String[]> returnScanner() throws Exception {
Tree tree = new Tree();
return tree.storing;
}
public static void main(String[] args) throws Exception{
ArrayList<String[]> storedValues = returnScanner();
String[] firstLine = storedValues.get(0);
String[] secondLine = storedValues.get(1);
for(int i = 0; i < firstLine.length; i++) {
System.out.println(firstLine[i]);
}
}
}
This doesnt make the things I want it to do, but I dont understand how to implement it, I guess it could just copy the coordinates to a text-file but I want it to work for all sorts of TSPS. Thanks in advance!
made a few changes here. I read up to "NODE_COORD_SECION" then start parsing ans storing the lines. Instead of splitting on "" I split on " " and store the values.
public class Tree {
ArrayList<String[]> storing;
public Tree() throws Exception {
File file = new File("C:/Users/joaki/Desktop/burma14.tsp");
Scanner sc = new Scanner(file);
storing = new ArrayList<String[]>();
String nextValue = null;
while (sc.hasNextLine()) {
String line = sc.nextLine();
if("NODE_COORD_SECTION".equals(line)){
while (sc.hasNextLine()) {
nextValue = sc.nextLine();
storing.add(nextValue.trim().split(" "));
}
}
}
sc.close();
}
public static ArrayList<String[]> returnScanner() throws Exception {
Tree tree = new Tree();
return tree.storing;
}
public static void main(String[] args) throws Exception {
ArrayList<String[]> storedValues = returnScanner();
String[] firstLine = storedValues.get(0);
String[] secondLine = storedValues.get(1);
for (int i = 0; i < firstLine.length; i++) {
System.out.println(firstLine[i]);
}
}
}
My output:
1
565.0
575.0
Use the scanner to move to the next line until it encounters the phrase "NODE_COORD_SECTION". Then the subsequent lines are you data lines. They all conform to the format so you can use split to get the 2nd and third elements.
Stop reading and storing in your array when you reach a line which states "EOF".
How much do you care about the header of the TSP file? If you want to store this information and check that it is correct against the data in the file, rather than just running to the line "NODE_COORD_SECTION" you would want to look for the line: "DIMENSION" and store the value as an int. Then check this value against your final total in your ArrayList "storing"
I want to do a terminal Graphic lib for funny and have seem many cool responsity, such as, asciimoo/drawille.
Using \r can redraw current line but how about former line?
For example, I have output three line(perhaps shouldn't use \n):
print("00000\n")
print("0 0\n")
print("00000\n")
//output
00000
0 0
00000
at next frame(eg. after 0.1s), I want redraw the second and third line. Hope result as:
00000
00 00
00 00
how to do this in terminal?
This will set up a console that has different states based on what the user enters. For now I just have the ability to go up ("w") or go down ("s")
public static void main(String[] args) {
HashMap<Integer, HashMap<String, String>> consoleStates = CreateConsoleStates();
String input = "default";
Scanner userInput = new Scanner(System.in);
do {
//draw default state of board
if(input.equals("default") || input.equals("w") || input.equals("s"))
printConsole(input, consoleStates);
//get input from user until they exit
input = userInput.nextLine().replaceAll("\n", "");
} while (!input.equals("exit"));
}//main method
public static HashMap<Integer, HashMap<String, String>> CreateConsoleStates()
{
HashMap<Integer, HashMap<String, String>> consoleStates = new HashMap<>();
HashMap<String, String> line1, line2, line3;
line1 = new HashMap<>();
line1.put("default", "00000");
line1.put("w", "00000");
line1.put("s", "00 00");
line2 = new HashMap<>();
line2.put("default", "0 0");
line2.put("w", "00 00");
line2.put("s", "00 00");
line3 = new HashMap<>();
line3.put("default", "00000");
line3.put("w", "00 00");
line3.put("s", "00000");
consoleStates.put(1, line1);
consoleStates.put(2, line2);
consoleStates.put(3, line3);
return consoleStates;
}
public static void printConsole(String state, HashMap<Integer, HashMap<String, String>> consoleStates)
{
//adding this will make it seem like a brand new console as suggested in another answer
//System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
//each number corresponds to the line in the console
System.out.println(consoleStates.get(1).get(state));
System.out.println(consoleStates.get(2).get(state));
System.out.println(consoleStates.get(3).get(state));
}
}
Output looks like:
00000
0 0
00000
s
00 00
00 00
00000
w
00000
00 00
00 00
e
00000
0 0
00000
exit
Note: that I'm using the standard wsad controls that most games have. I recommend it. w for up, a for left, s for down and d for right. Also i display the default state whenever an incorrect key is pressed and "exit" is used to exit the game.
I have the following example text:
Peter Miller - Product Management ### 20000
Now I want to let my users define an easy matching pattern with the help of the percent characters, like:
%NAME% - %JOB% ### %AMOUNT%
The order of the variables and the characters between them can change!
Does anybody know an existing ready to use implementation for this matching problem? I think RegExp is the wrong approach for this.
I think that you can create a regexp from your pattern, and match it against the text.
Here is a quick example:
public static Map<String, String> match(final String pattern, final String text) {
final StringBuilder regexp = new StringBuilder("^");
final List<String> varNames = new LinkedList<String>();
int i=0;
for (final String subPart : pattern.split("%", -1)) {
if (i++%2!=0) {
regexp.append("(.*)");
varNames.add(subPart);
} else {
regexp.append(Pattern.quote(subPart));
}
}
regexp.append("$");
final Pattern p = Pattern.compile(regexp.toString());
final Matcher m = p.matcher(text);
final Map<String, String> matched = new HashMap<String, String>();
if (m.matches()) {
int j=1;
for (final String varName : varNames) {
matched.put(varName, m.group(j++));
}
}
return matched;
}
You can call it like that:
public static void main(String[] args) {
final String pattern = "%NAME% - %JOB% ### %AMOUNT%";
final String text = "Peter Miller - Product Management ### 20000";
for (final Entry<String, String> e : match(pattern, text).entrySet()) {
System.out.println(e.getKey()+"\t"+e.getValue());
}
}
And the output is:
NAME Peter Miller
JOB Product Management
AMOUNT 20000
The code I'm looking at make's a URL call that returns a string made up off points for plotting a chart.[14.1(point),1363649400(timestamp in UTC will be converted later)]
String = [14.1,1363649400],[14.4,1363650300],[14.6,1363651200],[15.1,1363652100],[14.3,1363653000],[14.2,1363653900],[14.8,1363654800]................
The best way seems to be to remove square brackets and then use String.split().
So wondering if anyone had better idea's on how to convert this string to a Map, say.
This will take care of parsing and building the map. The map will also be sorted by timestamp.
final Matcher m = Pattern.compile("\\[(.*?),(.*?)\\]").matcher(input);
final Map<Long, Double> points = new TreeMap<>();
while (m.find())
points.put(Long.parseLong(m.group(2), Double.parseDouble(m.group(1)));
Like so:
points[] = string.substring(1, string.length()-1).split("],[");
which would result in an array of
"1,3", "3,4"
Create a class to hold your data objects:
private static final class Data {
private final BigDecimal point;
private final Date date;
public Data(final String point, final String date) {
this.point = new BigDecimal(point);
this.date = new Date(Long.parseLong(date));
}
#Override
public String toString() {
return "Data{" + "point=" + point + ", date=" + date + '}';
}
}
Now parse the string using a regex pattern, building the Data objects as you go. I have used possessive matchers as the String is presumably quite long and you don't want the express engine to backtrack along it repeatedly trying to match.
The Data can, as here, even parse the individual Strings to the real data types.
public static void main(String[] args) {
final String s = "[14.1,1363649400],[14.4,1363650300],[14.6,1363651200],[15.1,1363652100],[14.3,1363653000],[14.2,1363653900],[14.8,1363654800]";
final Pattern p = Pattern.compile("\\[([^,]++),(\\d++)\\]");
final Matcher matcher = p.matcher(s);
final Collection<Data> datas = new LinkedList<Data>();
while (matcher.find()) {
datas.add(new Data(matcher.group(1), matcher.group(2)));
}
for (final Data data : datas) {
System.out.println(data);
}
}
Output:
Data{point=14.1, date=Fri Jan 16 19:47:29 GMT 1970}
Data{point=14.4, date=Fri Jan 16 19:47:30 GMT 1970}
Data{point=14.6, date=Fri Jan 16 19:47:31 GMT 1970}
Data{point=15.1, date=Fri Jan 16 19:47:32 GMT 1970}
Data{point=14.3, date=Fri Jan 16 19:47:33 GMT 1970}
Data{point=14.2, date=Fri Jan 16 19:47:33 GMT 1970}
Data{point=14.8, date=Fri Jan 16 19:47:34 GMT 1970}
Obviously you can put those Data into a Map or Set or whatever suits you.
Using a regular expression doesn't seem to be the best approach, at least to me. The performance of regex in java is, to be honest, really bad. I'd write a parser myself, which would only take O(n) n being the length of the string.
How I'd do it:
public void splitSequence(String str) {
List<Double> lstPoint = new ArrayList<>();
List<Long> lstTime = new ArrayList<>();
char[] buf = new char[128];
int i=0;
boolean isPoint = true;
for(Character c : str.toCharArray()) {
if(c == ',') {
if(isPoint) {
lstPoint.add(new Double(new String(buf,0,i)));
isPoint = false;
}
else {
lstTime.add(Long.parseLong(new String(buf,0,i)));
isPoint = true;
}
buf = new char[128];
i=0;
} else if(!(c == '[' || c == ']')) {
buf [i++] = c;
}
}
}
//usage
splitSequence("[14.1,1363649400],[14.4,1363650300],[14.6,1363651200],[15.1,1363652100],[14.3,1363653000],[14.2,1363653900],[14.8,1363654800]");