How to read Java files with contain many splits - java

BB [FL:60 BT:10 SG:20 MK:10 | 12]
I have above data on a text file and I need to get integer values separately
In brief first BB represent food type
with ":" split represents materials
and with "|" represent time to make it
How can i get those 5 parameters in java using File reader Thank you

Use a regex matcher here, and iterate over your input string, matching pure numbers as you go along:
String input = "BB [FL:60 BT:10 SG:20 MK:10 | 12]";
String regex = "\\d+(?=[^0-9.])";
List<Integer> vals = new ArrayList<>();
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
while (m.find()) {
vals.add(Integer.parseInt(m.group(0)));
}
for (int val : vals) {
System.out.println("Found an integer: " + val);
}
Found an integer: 60
Found an integer: 10
Found an integer: 20
Found an integer: 10
Found an integer: 12
Demo

Split, split, trim & split:
-> String code = "BB [FL:60 BT:10 SG:20 MK:10 | 12]"
| Added variable code of type String with initial value "BB [FL:60 BT:10 SG:20 MK:10 | 12]"
-> String[] mattime = code.split ("[\\]\\[\\|]");
| Modified variable mattime of type String[] with initial value [Ljava.lang.String;#2286778
| Update overwrote variable mattime
-> mattime [1]
| Expression value is: "FL:60 BT:10 SG:20 MK:10 "
| assigned to temporary variable $32 of type String
-> String[] elem = mattime [1].split (" ")
| Modified variable elem of type String[] with initial value [Ljava.lang.String;#13a5fe33
| Update overwrote variable elem
-> for (String e: elem) println (e);
FL:60
BT:10
SG:20
MK:10
-> for (String e: elem) {println (e); String [] kv = e.trim().split (":") ; println (kv[0] + " : " + Integer.parseInt (kv[1])); }
FL:60
FL : 60
BT:10
BT : 10
SG:20
SG : 20
MK:10
MK : 10

Related

Verify and replace id to match a pattern in java?

I've a requirement where I'm getting a string that may or may not contain an s at the begining and then numbers that can be from 1 digit to 5 digits. Now, this string needs to be like the s and 5 digits (it cannot contain another letter), something like this:
s1 -> s00001
s12 -> s00012
s123 -> s00123
s1234 -> s01234
s12345 -> s12345
Because the s may or may not come, I need to check that too before adding the leading zeros.
This is what I got so far but is it there a better solution for this (maybe with regular expresions?
private String formatStoreNumber(String storeNumber) {
if(storeNumber.contains("s")) {
storeNumber = storeNumber.replace("s", "");
}
storeNumber = StringUtils.leftPad(storeNumber, 5, '0');
storeNumber = "s" + storeNumber;
return storeNumber;
}
You can try the below solution :
private static String formatStoreNumber(String storeNumber) {
String strWithoutS = storeNumber.replaceAll("S", "");
String result = "S" + ("00000" + strWithoutS).substring(strWithoutS.length());
return result;
}
Below are the input and respective output:
Input : S14666| Output : S14666
Input : 1 | Output : S00001
Input : 12 | Output : S00012
Input : 123 | Output : S00123
Input : 1234 | Output : S01234
Input : 12345 | Output : S12345

what is the best way to find the topper by subject?

I have a string array of student info:
StudentNumber Integer, Subject String, mmarks integer
What would be the best way to use the java & collection to find out the topper in each subject.
ArrayList<String> strings = new ArrayList<String>();
strings.add("1 | Computers | 48");
strings.add("2 | Data Structures | 89");
strings.add("33 | English | 35");
strings.add("24 | Maths | 70");
strings.add("15 | Computers | 58");
strings.add("6 | Data Structures | 55");
strings.add("7 | English | 40");
strings.add("18 | Maths | 73");
for (String str : strings) {
String [] strArray = str.split("\\|");
// in completed code
for (int i = 0; i < str.length(); i++) {
sam.put(strArray[0], strArray[2]);
s.add(strArray[1]);
}
}
Expected output
15 Computers
2 Data structures
7 English
18 Maths
Create a Result class to store the information:
class Result {
private int studentNumber;
private String subject;
private int mark;
// constructor, getters and setters go here ...
}
Now convert your List<String> to a List<Result>:
List<Result> results = new ArrayList<>();
for (String s : strings){
String[] sa = s.split(" \\| ");
results.add(new Result(Integer.parseInt(sa[0]), sa[1], Integer.parseInt(sa[2])));
}
Create a stream from the results list, group by subject, and find the student with the highest mark:
Map<String, Integer> map = results.stream()
.collect(Collectors.groupingBy(Result::getSubject,
Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(Result::getMark)), r -> r.get().getStudentNumber())));
Print the result:
map.forEach((k,v) -> System.out.println(v + " " + k));
15 Computers
18 Maths
7 English
2 Data Structures

How to get text between delimiters in specific positions/indices in a concise way (e.g regular expression)?

I have strings with specific delimiters like
String str = "some other text # test text between # another text # extra text";
What I am trying to do is given two indices I want to get the in between text of those delimiters without the delimiters..
So for:
("#", 0,1) => "test text between"
("#", 1,2) => "another text"
("#", 0,2) => "test text between another text"
I know how to do it using a StringTokenizer/split. Something along those lines:
public static String getTextBetweenDelimiterPositions(String str, String delimiter, int fromIndex, int toIndex) {
if (fromIndex >= toIndex) return null;
StringTokenizer strTok = new StringTokenizer(str, delimiter, true);
int tokenIndex = 0;
StringBuilder keep = new StringBuilder();
while(strTok.hasMoreTokens()) {
String token = strTok.nextToken();
if (!token.equals(delimiter) && tokenIndex > fromIndex && tokenIndex <=toIndex) {
keep.append(token.trim()+" ");
}
if (token.equals(delimiter)){
tokenIndex++;
}
}
return keep.toString().trim();
}
I wonder if it is possible to do it with regular expressions for example.
Not in Java (in Perl with a Bash wrapper), but may be useful to demonstrate the general regex idea:
#!/bin/bash
s=" # " # delimiter
for a in $(seq 0 3); do
for b in $(seq $a 3); do
echo "$a $b"
echo "aaa # bbb # ccc # ddd # eee" | perl -nle "
if (m/(?:.*?$s){$a}((?:.*?$s){$[b-a]})/) { # if matches
# do some post-processing (replace " # " with "" etc.)
print '[', \$1 =~ s/$s/ /gr =~ s/ \$//r, ']'
}
"
done
done
Output:
0 2
[aaa bbb]
0 3
[aaa bbb ccc]
1 1
[]
1 2
[bbb]
1 3
[bbb ccc]
2 2
[]
2 3
[ccc]
3 3
[]

String#replaceAll() to replace *anything but a =* group

I have a parameter of key-value like this:
sign="aaaabbbb="
And I want to get the parameter name sign and the value "aaaabbb="(with quote signs)
I thought I could split the string with = to get the first elem of the array which is the parameter name and do a String.replaceAll() to remove the sign= to get the value. Anyway here is my sample code:
public class TestStringReplace {
public static void main(String[] argvs){
String s = "sign=\"aaaabbbb=\"";
String[] ss = s.split("=");
String value = s.replaceAll("\\[^=]+=","");
//EDIT: s.replaceAll("[^=]+=","") will not do the job either.
System.out.println(ss[0]);
System.out.println(value);
}
}
but the output shows this:
sign
sign="aaaabbbb="
Why \\[^=]+= not matching sign= and replace it with empty string here?Quite a newbie of Java regex, need some help.
Thanks in advance.
In Java you can use the following:
String str = "sign=\"aaaabbbb=\"";
String var1 = str.substring(0, str.indexOf('='));
String var2 = str.substring(str.indexOf('=')+1);
System.out.println("var1="+var1+", var2="+var2);
The above would have the following output:
var1=sign, var2="aaaabbbb="
Try the following regex ^\\w+= with replaceAll() instead of your regex:
public class TestStringReplace {
public static void main(String[] argvs){
String s = "sign=\"aaaabbbb=\"";
String[] ss = s.split("=");
String value = s.replaceAll("^\\w+=","");
System.out.println(ss[0]);
System.out.println(value);
}
}
This will remove the sign=.
You can see the DEMO here.
Note that with your "\\[^=]+=" regex you were trying to match the character [ literally in the beginning of your regex.
And it explains why you got sign="aaaabbbb=" as a result with replaceAll() which didn't replace anything because there's no match.
You're probably better off with an actual Pattern and back-references here.
For instance:
String[] test = {
"sign=\"aaaabbbb=\"",
// assuming a HTTP GET-styled parameter list
"blah?sign=\"aaaabbbb=\"",
"foo?sign=\"aaaabbbb=\"&blah=\"hodor\""
};
// | group 1: literal "sign"
// | | literal key-value delimiter and double quote
// | | | group 2: any character reluctantly quantified
// | | | | literal ending double quote
// | | | | | look-ahead for either "&" or end
// | | | | |
Pattern p = Pattern.compile("(sign)=\"(.+?)\"(?=$|&)");
Matcher m = null;
for (String s: test) {
m = p.matcher(s);
while (m.find()) {
System.out.printf(
"Found key: \"%s\" and value: \"%s\"%n", m.group(1), m.group(2)
);
}
}
Output
Found key: "sign" and value: "aaaabbbb="
Found key: "sign" and value: "aaaabbbb="
Found key: "sign" and value: "aaaabbbb="
Notes
I'm assuming a HTTP GET styled parameter list, but maybe you don't need to actually check for a next parameter key-value pair delimiter (i.e. &) - in which case you can remove the & part
I'm also assuming you want the "s out of your value back-reference, which kind of makes the following & check useless
Your current pattern for the replaceAll invocation will match as follows:
// | literal "[" (double-escaped)
// ||literal "^" or "=" (in character class)
// || | ... greedily quantified (1+ occurrences)
// || || literal "="
"\\[^=]+="
Finally, if you really, really want to use String#replaceAll for this, here's a slightly different pattern than the one above:
for (String s: test) {
System.out.println(
s.replaceAll(
".*(sign)=\"(.+?)\"(?=$|&).*",
"Found key: \"$1\" and value: \"$2\""
)
);
}
It still uses back-references and will produce the same result, albeit in a uglier way: you can't reuse the $1 and $2 group values, since you're creating a new String replacing the original one.
Last possible solution, using String#'split. This is the ugliest as it won't work well with a list of parameters:
for (String s: test) {
System.out.println(
// | negative look-behind for start of input
// | | literal "="
// | | | literal "
// | | |
Arrays.toString(s.split("(?<!^)=\""))
);
}
Output
[sign, aaaabbbb]
[blah?sign, aaaabbbb] --> yuck
[foo?sign, aaaabbbb, &blah, hodor"] --> yuck again
The double slash is a mistake, because it is escaping the [ to a literal [, which will never match.
Instead, do this:
String name = s.replaceAll("=.*", "");
String value = s.replaceAll(".*?=", "");

ANTLR text containing tokens - SWIFT newline colon

I'm trying to parse some messages using an ANTLR grammar. Messages carry the structure:
:20:REF123456
:72:Some narrative text which
may contain new lines and
occassionally other : characters
:80A:Another field
The target output is a table containing the text between the colons as a 'key' and the text until the next key as the value of that key. For example:
Key | Values
--------------------------------------
20 | REF123456
72 | Some narrative text which
may contain new lines and
occassionally other : characters
80 | Another field
I'm able to write a grammar to do this, as long as colons are not allowed in the value field based on the following reference http://danielveselka.blogspot.fr/2011/02/antlr-swift-fields-parser.html
Can anyone offer guidance on how to approach this problem?
I'd skip v3 and go with ANTLR v4. A quick demo of how to do this in v4 would look like this:
grammar Swift;
parse
: entries? EOF
;
entries
: entry ( LINE_BREAK entry )*
;
entry
: key value
;
key
: ':' DATA ':'
;
value
: line ( LINE_BREAK line )*
;
line
: ( DATA | SPACES ) ( COLON | DATA | SPACES )*
;
LINE_BREAK
: '\r'? '\n'
| '\r'
;
COLON
: ':'
;
DATA
: ~[\r\n: \t]+
;
SPACES
: [ \t]+
;
Now all you need to do now is attach a listener to a tree-walker and listen for enterEntry occurrences and capture the key and value text. Here's how to do that:
public class Main {
public static void main(String[] args) throws Exception {
String input = ":20:REF123456\n" +
":72:Some narrative text which\n" +
"may contain new lines and\n" +
"occassionally other : characters\n" +
":80A:Another field";
SwiftLexer lexer = new SwiftLexer(new ANTLRInputStream(input));
SwiftParser parser = new SwiftParser(new CommonTokenStream(lexer));
ParseTreeWalker.DEFAULT.walk(new SwiftBaseListener(){
#Override
public void enterEntry(#NotNull SwiftParser.EntryContext ctx) {
String key = ctx.key().getText().replace(":", "");
String value = ctx.value().getText().replaceAll("\\s+", " ");
System.out.printf("key -> %s\nvalue -> %s\n================\n", key, value);
}
}, parser.parse());
}
}
Running the demo above will print the following on your console:
key -> 20
value -> REF123456
================
key -> 72
value -> Some narrative text which may contain new lines and occassionally other : characters
================
key -> 80A
value -> Another field
================

Categories

Resources