How to parse a fixed width file using Java? - java

I am working on a small project, and it's mostly working out. The whole purpose is to take a file loop through it, and each individual line gets delimited in some manner. I've done that for commas, pipes, etc, but I also need to do a fixed width version. I wrote the code below, which should take find all the elements on the line isolate only the ones with a string value, and add it to an arrayList.
Right now it adds the first value, and then a series of commas to represent the whitespace, but it never gets to the 2nd string value.
public static List fwListCreator(String str) throws IOException {
List<String> fixedWidthList = new ArrayList<String>();
char[] charArray = str.toCharArray();
List<List<Boolean>> zeroWhite = new ArrayList<>();
zeroWhite.add(new ArrayList<Boolean>());
List<Boolean> temp = zeroWhite.get(0);
//add all non-whitespace character from string
for (char ch : charArray) {
temp.add(!Character.isWhitespace(ch));
}
System.out.println(temp);
//get all nonwhitespace characters per column
int maxLine = zeroWhite.stream().mapToInt(e -> e.size()).max().orElse(0);
System.out.println(maxLine);
//max number of characters in row.
int[] charCountArray = new int[maxLine];
//counting all non-whitespace per column
for (List<Boolean> row : zeroWhite) {
for (int columnChars = 0; columnChars < row.size(); ++columnChars) {
if (row.get(columnChars)) {
++charCountArray[columnChars];
}
}
}
//overview of non-white columns
Map<Integer, Long> potentialMap = (Map<Integer, Long>) Arrays.stream(charCountArray).mapToObj(i -> (Integer)i).collect(Collectors.groupingBy( Function.identity(), // their identity (value)
Collectors.counting()));
//minimum number of non-whitespace columns
int emptyIntVal = Collections.min(potentialMap.keySet());
//find delimited columns
List<Boolean> emptyListVal= Arrays.stream(charCountArray).mapToObj(n -> n == emptyIntVal).collect(Collectors.toList());
List<Integer> valIndices = new ArrayList<>();
for (int charCount = 0; charCount < maxLine; ++charCount) {
if (emptyListVal.get(charCount)) {
valIndices.add(charCount);
}
}
System.out.println(valIndices);
int indexSizeVal = valIndices.size();
valIndices.add(0,0);
int len = str.length();
//parse
for (int i = 1; i <= indexSizeVal; ++i) {
if (len < valIndices.get(i)) break;
fixedWidthList.add(str.substring(valIndices.get(i-1), valIndices.get(i)).trim());
}
return fixedWidthList
}
These are the 3 lines being passed in the file, 1 each time so str represents 1 of these lines at a time.
Ackerman Scott
Jones Steve
Gaiman Neil

Is this what you were looking for? I don't have any idea what your data source is so I just used a String[][]
public static String format(String[][] columns){
int[] maxSize = new int[columns[0].length];
for (int i = 0; i < maxSize.length; i++) {
int max = 0;
for (String[] column : columns) {
max = Math.max(max, column[i].length());
}
maxSize[i] = max;
}
StringBuilder sb = new StringBuilder();
for (String[] column : columns) {
for (int i = 0; i < column.length; i++) {
sb.append(String.format("%-" + maxSize[i] + "s", column[i]));
}
sb.append("\n");
}
return sb.toString();
}

Related

Replacing String in Java to get all variations

I'm trying to get a printout of all variations of a certain String. For example, we have this input: AB0C0. The 0 in the 3rd and 5th spots should be treated as variables. The variable characters are 1, 2, and 3 to be placed in the spot of 0. This means there would be all possible variations of this input:
AB1C1
AB2C1
AB3C1
AB1C2
AB1C3
AB2C2
AB2C3
AB3C2
AB3C3
This is just an example. A 5-character long string is a place for 1 to 5 variables. The issue I'm facing is, that it should generate all variations no matter how many variables are in the input in no matter in which place they are.
Scanner scanner = new Scanner (System.in);
System.out.println("Enter the key consisting of 5 characters:");
String input = scanner.next();
String strOutput1 = input.replaceFirst("0","1");
String strOutput1A = input.replace("0","1");
String strOutput2 = input.replaceFirst("0","2");
String strOutput3 = input.replaceFirst("0","3");
String strOutput4 = input.replaceFirst("0","4");
String strOutput5 = input.replaceFirst("0","5");
System.out.println(strOutput1.toUpperCase());
System.out.println(strOutput1A.toUpperCase());
System.out.println(strOutput2.toUpperCase());
System.out.println(strOutput3.toUpperCase());
System.out.println(strOutput4.toUpperCase());
System.out.println(strOutput5.toUpperCase());
What about this:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the key consisting of 5 characters:");
String input = scanner.next();
//find positions of '0' in input
List<Integer> varPositions = findVarPositions(input);
//create permutations
List<String> permutations = new ArrayList<>();
permutations.add(input);//AB0C0
for (int position : varPositions) {
permutations = permutateAtPosition(permutations, position);
}
//print permutations
for (String permutation : permutations) {
System.out.println(permutation.toUpperCase());
}
}
private static List<Integer> findVarPositions(String input) {
List<Integer> varPositions = new ArrayList<>();
int lastVarPosition = -1;
while ((lastVarPosition = input.indexOf('0', lastVarPosition + 1)) != -1) {
varPositions.add(lastVarPosition);
}
return varPositions;
}
private static List<String> permutateAtPosition(List<String> partialyPermutated, int position) {
List<String> result = new ArrayList<>();
char[] replacements = {'1', '2', '3', '4', '5'};
for (String item : partialyPermutated) {
for (int i = 0; i < replacements.length; i++) {
String output = replaceCharAt(item, position, replacements[i]);
result.add(output);
}
}
return result;
}
private static String replaceCharAt(String input, int position, char replacement) {
//converting to char array, because there's no method like
//String.replaceAtPosition(position, char)
char[] charArray = input.toCharArray();
charArray[position] = replacement;
return new String(charArray);
}
}
It's not fixed to a number of variables.
The idea is to extract positions of '0' and subsequently call the method permutateAtPosition, which takes a partially permutated list and permutates it by one more level.
For "a0b0c0" and values 1-2 it would be ['a0b0c0'], then ['a1b0c0','a2b0c0'], then ['a1b1c0','a1b2c0','a2b1c0','a2b2c0'], and finally ['a1b1c1','a1b1c2','a1b2c1','a1b2c2','a2b1c1','a2b1c2','a2b2c1''a2b2c2'].
This solution keeps everything in memory, so in the general case (unlimited input string) it would be wiser to go with depth-first instead.
I've got another solution for you.
First step, getting the amount of variables:
int variableCount = 0;
for (int i = 0; i < 5; i++) {
if (input.charAt(i) == '0') {
variableCount++;
}
}
Then calculating the amount of results we are expecting:
int countMax = (int)Math.pow(4,variableCount);
Lastly, count up in base 4. Pad the number with 0's and replace the original input 0's:
for (int i = 0; i < countMax; i++) {
String paddedNumbers = format("%" + variableCount + "s",Integer.toString(i, 4)).replace(" ", "0");
int replacedCount = 0;
char[] outputChars = input.toCharArray();
for (int j = 0; j < 5; j++) {
if (input.charAt(j) == '0') {
outputChars[j] = paddedNumbers.charAt(replacedCount);
replacedCount++;
}
}
System.out.println(outputChars);
}

Remove null from unused space of StringArray when converting to a string in Java

I was working on a Java coding problem and encountered the following issue.
Input: A String -> "Code"
Output Expected: A string -> CCoCodCode
My Code snippet: (Note: In comments I have written what I expect upon passing the string)
public String stringSplosion(String str) { // string Say 'Code'
String join = "", values = "";
String gotIt = "";
int n = str.length(); // 4
int size = 0;
for (int i = n; i >= 1; i--) {
size = size + n; // 4+3+2+1=10
}
String[] result = new String[size];
for (int i = 0; i < str.length(); i++) {
values = str.substring(i, i + 1);
join = join + values;
result[i] = join;
}
for (String s : result) {
gotIt = gotIt + s;
}
return gotIt; // Expected output: CCoCodCode
}
Output I am getting:
CCoCodCodenullnullnullnullnullnullnullnullnullnullnullnull
Why is null getting stored although I have reduced the size and how can I remove it?
NOTE: I need to solve this using arrays. I know it is much easier using List.
If you want to keep the current structure of your code, get rid of the first for loop.
And create String[] array = new String[n]
public static String stringSplosion(String str) { // string Say 'Code'
String join = "", values = "";
String gotIt = "";
int n = str.length(); // 4
String[] result = new String[n]; //you want your String array to contain 4 strings
for (int i = 0; i < str.length(); i++) {
values = str.substring(i, i + 1);
join = join + values;
result[i] = join;
}
for (String s : result) {
gotIt = gotIt + s;
}
return gotIt; // Expected output: CCoCodCode
}
public class Answer {
public static String answer(String input){
StringBuilder sb = new StringBuilder(((input.length() + 1) * input.length()) / 2);
for (int i = 1; i <= input.length(); i++) {
sb.append(input.substring(0, i));
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(answer("Code"));
}
}
Below statements are not required:
int size = 0;
for (int i = n; i >= 1; i--) {
size = size + n; // 4+3+2+1=10
}
You just need to change the array size from
String[] result = new String[size];
to
String[] result = new String[n];
for your program to give the expected output.
If I understand ur problem correctly to print the pattern then u can use below code,
public String printPattern(String input){
//Holds the iteration value by index
int previous=0;
//It holds the result characters
String result=null;
StringBuilder strBuilder=new StringBuilder();
//first loop to iterate only till input string length
for(int i=0;i<input.length();i++){
//checking iteration lenght with input string length
if(previous<input.length()){
//incrementing iteration for reading characters from input string
previous++;
//main loop for previous iteration value check and iterate
for(int j=0;j<previous;j++){
//converting string to Character array
char a []=input.toCharArray();
//using string builder to build the string from characters
strBuilder.append((a[j]));
//setting the value to stringbuilder by converting it in string
result=strBuilder.toString();
}
}
}
return result;
}
Size should be the length of string. Code's length is 4. Code will produce {C, Co, Cod, Code}.
public String stringSplosion(String str) { // string Say 'Code'
String join = "", values = "";
String gotIt = "";
int n = str.length(); // 4
String[] result = new String[n];
for (int i = 0; i < str.length(); i++) {
values = str.substring(i, i + 1);
join = join + values;
result[i] = join;
}
System.out.println(Arrays.toString(result));
for (String s : result) {
gotIt = gotIt + s;
}
return gotIt; // Expected output: CCoCodCode
}
String input = "Code";
String output[] = IntStream.range(0, input.length()+1)
.mapToObj(i -> input.substring(0, i))
.toArray(String[]::new);

Complete a String containing comma and dot separated integers

Question:
Given an input String like "1,2,3..6..8,9..11", we have to convert it into "1,2,3,4,5,6,7,8,9,10,11". So basically we have to populate the ranges mentioned by dots. Below is my solution. Is there any better way to solve this ? Can we optimize this further ?
public class FlattenAString {
public static String flattenAString(String input) {
StringBuilder sbr = new StringBuilder("");
StringBuilder current = new StringBuilder("");
StringBuilder next = new StringBuilder("");
int i = 0;
while (i < input.length()) {
if (input.charAt(i) == '.') {
i = i + 2;
while (i != input.length() && input.charAt(i) != '.' && input.charAt(i) != ',') {
next.append(input.charAt(i));
i++;
}
int currentInt = Integer.parseInt(current.toString());
int nextInt = Integer.parseInt(next.toString());
appendFromCurrentTillPrevToNextInt(currentInt, nextInt, sbr);
current = next;
next = new StringBuilder("");
} else if (input.charAt(i) == ',') {
sbr.append(current);
sbr.append(',');
current = new StringBuilder("");
i++;
} else {
current.append(input.charAt(i));
i++;
}
}
sbr.append(current);
return sbr.toString();
}
private static void appendFromCurrentTillPrevToNextInt(int current, int val, StringBuilder sbr) {
for (int i = current; i < val; i++) {
sbr.append(i);
sbr.append(',');
}
}
}
I would approach this by splitting your input string twice. First, split by comma to get either single numbers or ranges with ellipsis. For single numbers, simply add them to a list. For ranges, do a second split on .. to obtain another list of numbers. Then iterate over the range of each of these pairs to fill in the missing values.
Note one tricky point here is that we need to avoid double counting a number position in a range. This is best explained by example:
3..6..8
For this range, we first add 3, 4, 5, 6. But for the second ellipsis, we begin at 7, and then continue until hitting 8.
String input = "1,2,3..6..8,9..11";
String[] parts = input.split(",");
List<Integer> list = new ArrayList<>();
for (String part : parts) {
if (!part.contains("..")) {
list.add(Integer.parseInt(part));
}
else {
String[] ranges = part.split("\\.\\.");
for (int i=0; i < ranges.length-1; ++i) {
int start = Integer.parseInt(ranges[i]) + (i == 0 ? 0 : 1);
int end = Integer.parseInt(ranges[i+1]);
for (int j=start; j <= end; ++j) list.add(j);
}
}
}
// print list of numbers
for (int i=0; i < list.size(); ++i) {
System.out.print((i > 0 ? ", " : "") + list.get(i));
}
Output:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
Demo here:
Rextester
Try this.
static final Pattern RANGE = Pattern.compile("(\\d+)(\\.\\.(\\d+))+");
static String flattenString(String input) {
StringBuffer sb = new StringBuffer();
StringBuilder temp = new StringBuilder();
Matcher m = RANGE.matcher(input);
while (m.find()) {
int begin = Integer.parseInt(m.group(1));
int end = Integer.parseInt(m.group(3));
temp.setLength(0);
for (int i = begin; i <= end; ++i)
temp.append(",").append(i);
m.appendReplacement(sb, temp.substring(1));
}
m.appendTail(sb);
return sb.toString();
}

Convert a number-word (String) to its Integer Value

EDIT: right, I forgot to state the problem -- which is the fact that I get 0 as an output.
CONTEXT
My program aims to take a user-inputted number-word (1- 99) and output it as an integer (i.e. thirty-four = 34). I can't figure out where the error in my code is and need help:
Scanner scInput = new Scanner(System.in);
String word = scInput.nextLine(); //number in word-form (i.e. twenty six)
char[] charArray = word.toCharArray();//string to char array for word^
int divider = 0; //position of hyphen/space in charArray
All 2-word numbers are comprised of a tens value & a ones value. Assuming proper syntax [english], the word before the hyphen/space divider is the tens and the word following divider is the ones.
ARRAYS
//word values - components & syntax (1-99)
//ONES
public static final String[] wONES = {"one","two","three","four","five","six","seven","eight","nine"};
//TENS
public static final String[] wTENS = {null,"twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"};
//TEENS
public static final String[] wTEENS = {"ten", "eleven", "twelve", "thirteen","fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
I've organized all the word-components into 3 different arrays: ones, tens, and teens.
//equivalent integer-array of above String arrays
//ONES
public static final int[] nONES = {1,2,3,4,5,6,7,8,9};
//TENS
public static final int[] nTENS = {0,20,30,40,50,60,70,80,90};
//TEENS
public static final int[] nTEENS = {10,11,12,13,14,15,16,17,18,19};
I created 3 other arrays that are the same as the above three arrays, except they store the integer values.
CODE
Here I separate the user-inputted String into two sections: the tens and the ones. So if the number was 72: 70 = tens and 2 = ones.
int tensValue = 0; //number's tens value (i.e. 30)
int onesValue = 0; //ones value (i.e. 3)
char[] tensArray = null; //array storing tens section of word (before divider)
for (int u = 0; u < divider; u++){
tensArray[u] = charArray[u];
}
String tens = new String(tensArray); //convert char array to String
char[] onesArray = null; //array storing ones section of word (after divider)
for (int u = divider + 1; u > divider && u < charArray.length; u++){
onesArray[u] = charArray[u];
}
String ones = new String(onesArray);
//searches for matches in String array for tens
for(int u = 0; u < wTENS.length; u++){
if(tens.equals(wTENS[u])){
tensValue = nTENS[u];
total += tensValue;
}
}
//searches for matches in String array for ones
for(int u = 0; u < wONES.length; u++){
if(ones.equals(wONES[u])){
onesValue = nONES[u];
total += onesValue;
In your current code you are doing char[] tensArray = null; which should be something like char[] tensArray = new char[10]; or else you end up with NPE.
It might not be most efficient but here is a simple and better approach to your problem.
Read the line and split it on white space (assuming you are separating your words by a space).
Search each of the tokens you get after split in the above lists and add the corresponding number (same index) to your answer.
Print the answer.
Here is the code snippet:
class Main
{
public static final String[] wONES = {"one","two","three","four","five","six",
"seven","eight","nine"};
public static final String[] wTENS = {"ten","twenty","thirty","forty","fifty","sixty",
"seventy","eighty","ninety"};
public static final String[] wTEENS = {"eleven", "twelve", "thirteen","fourteen",
"fifteen", "sixteen", "seventeen", "eighteen",
"nineteen"};
public static final int[] nONES = {1,2,3,4,5,6,7,8,9};
public static final int[] nTENS = {10,20,30,40,50,60,70,80,90};
public static final int[] nTEENS = {11,12,13,14,15,16,17,18,19};
public static void main (String[] args) throws Exception
{
Scanner scInput = new Scanner(System.in);
String word = scInput.nextLine();
int answer = 0;
/* Assuming you are giving space between words */
for(String s : word.split(" ")) {
/* Scan wONES */
for(int i = 0; i < wONES.length; i++) {
if(wONES[i].equalsIgnoreCase(s)) {
answer += nONES[i];
continue;
}
}
/* Scan wTENS */
for(int i = 0; i < wTENS.length; i++) {
if(wTENS[i].equalsIgnoreCase(s)) {
answer += nTENS[i];
continue;
}
}
/* Scan wTEENS */
for(int i = 0; i < wTEENS.length; i++) {
if(wTEENS[i].equalsIgnoreCase(s)) {
answer += nTEENS[i];
continue;
}
}
}
System.out.println("Result: " + answer);
}
}
Input:
thirty four
Output:
34
You have an interesting approach to this problem. A couple of things to change:
I don't see where you set your divider index.
You seem to be doing a lot of work with character arrays, so I'm guessing you're coming from a different language. Sticking with Strings will work fine.
You don't address the "teens". This looks like a simple oversight.
I've added those fixes while attempting maintain the original approach:
public static void main(String [] args) {
Scanner scInput = new Scanner(System.in);
String word = scInput.nextLine();
int total = 0;
int tensValue = 0; //number's tens value (i.e. 30)
int onesValue = 0; //ones value (i.e. 3)
int divider = word.indexOf('-');
String tens = null;
String ones = null;
if (divider != -1) {
tens = word.substring(0, divider);
ones = word.substring(divider + 1);
} else {
ones = word;
}
//searches for matches in String array for tens
if (tens != null) {
for (int u = 0; u < wTENS.length; u++) {
if (tens.equals(wTENS[u])) {
tensValue = nTENS[u];
total += tensValue;
}
}
}
//searches for matches in String array for ones
for(int u = 0; u < wONES.length; u++) {
if (ones.equals(wONES[u])) {
onesValue = nONES[u];
total += onesValue;
}
}
// if a "teen" override what's in total
for(int u = 0; u < wTEENS.length; u++) {
if (ones.equals(wTEENS[u])) {
total = nTEENS[u];
}
}
System.out.println(total);
}

null pointer exception string builder

I am trying to use the setCharAt method in a StringBuilder but I am getting a null pointer exception. Is there a way I can add values to the StringBuilder array I have made so I wont get these error.
From research I have found the .append() method but I'm not even sure how it works.
import java.util.*; // Allows for the input of a scanner method.
import java.io.*; // Allows for the inputting and outputting of a data file.
import java.lang.*; // Allows for the use of String Methods.
//////////////////////////////////////////////////////////////////////////////////////
public class TESTY
{
static Scanner testanswers;
static PrintWriter testresults;
public static void main(String[] args) throws IOException
{
testanswers = new Scanner(new FileReader("TestInput.dat"));
testresults = new PrintWriter("TestOutput.dat");
String StudentID;
String answers;
// Reads first two lines first to know how many records there are.
String answerKey = testanswers.nextLine();
int count = Integer.parseInt(testanswers.nextLine());
// Allocate the array for the size needed.
String[][] answerArray = new String[count][];
for (int i = 0; i < count; i++)
{
String line = testanswers.nextLine();
answerArray[i] = line.split(" ", 2);
}
for(int row = 0; row < answerArray.length; row++)
{
for(int col = 0; col < answerArray[row].length; col++)
{
System.out.print(answerArray[row][col] + " ");
}
System.out.println();
}
gradeData(answerArray, answerKey);
testanswers.close();
testresults.close();
}
///////////////////////////////////////////////////////////
//Method: gradeData
//Description: This method will grade testanswers showing
//what was missed, skipped, letter grade, and percentage.
///////////////////////////////////////////////////////////
public static double gradeData(String[][] answerArray, String answerKey)
{
String key = answerKey;
double Points = 0;
StringBuilder[] wrongAnswers = new StringBuilder[5];
String studAnswers;
for(int rowIndex = 0; rowIndex < answerArray.length; rowIndex++) /// Counting rows
{
studAnswers = answerArray[rowIndex][1].replace(" ", "S"); ///Counts rows, Col stay static index 1
for(int charIndex = 0; charIndex < studAnswers.length(); charIndex++)
{
if(studAnswers.charAt(charIndex) == key.charAt(charIndex))
{
Points += 2;
}
else if(studAnswers.charAt(charIndex) == 'S')
{
Points --;
}
else if(studAnswers.charAt(charIndex) != key.charAt(charIndex))
{
for(int i = 0; i < wrongAnswers.length; i++)
{
wrongAnswers[i].setCharAt(charIndex, 'X');
}
Points -= 2;
}
}
System.out.println(Points);
}
return Points;
}
}
The error is occurring on line 91 :
wrongAnswers[i].setCharAt(charIndex, 'X');
You have declared an array of StringBuilders, but you haven't initialized any of the slots, so they're still null.
Initialize them:
StringBuilder[] wrongAnswers = new StringBuilder[5];
for (int i = 0; i < wrongAnswers.length; i++)
{
wrongAnswers[i] = new StringBuilder();
}
Additionally, using setCharAt won't work here, because initially, there is nothing in the StringBuilder. Depending on what you want here, you may need to just call append, or you may initially want a string full of spaces so that you can set a specific character to 'X'.
StringBuilder[] wrongAnswers = new StringBuilder[5];
does not create 5 empty StringBuilders but 5 null StringBuilders.
You need to call something like
wrongAnswers[i] = new StringBuilder()
in order to initialize your 5 array members.
Your problem is that
StringBuilder[] wrongAnswers = new StringBuilder[5];
does not create 5 StringBuilder objects. It only creates an array with 5 null StringBuilder references. You need to create each StringBuilder separately with a line such as
wrongAnswers[i] = new StringBuilder();
inside a loop over i.

Categories

Resources