I need to be able to count a line every time text is wrapped. I am using the javaFX "TextArea" control.
I have implemented a counter that is incremented every time a "\n" character is encountered. Unfortunately, this ignores the additional lines created due to text wrapping.
There IS a way to circumvent this using the jtextarea swing control, which is similar to javafx's text area, but I don't really want to use it because the FX version has other pieces of functionality which are much better suited to my tasks.
If anyone has any suggestions about how to increment this counter, please let me know! Alternatively, another way to count lines would be just as effective.
(I'm using scene builder 2.0 in conjunction with Netbeans 8.1/8.0.2 (both))
I had to manually put in the newline characters as follows:
String pText = Primary.getText();
Primary.clear();
StringReader reader = new StringReader(pText);
BufferedReader br = new BufferedReader(reader);
//FileReader reader = new FileReader(fileLocation);
//BufferedReader br = new BufferedReader(reader);
String s;
int index = 0;
//int charCounter = 0;
boolean endOfPara = false;
// int index = 0;
// boolean endOfPara = false;
try{
//loads the text and formats it if necessary
while((s = br.readLine()) != null)
{
index = 0;
//loading block
if(s.length() <= characterCapacity)
{
//String s = "abcdefg";
int result = s.indexOf('\n');
if(result == -1)
{
Primary.appendText(s + "\n");
}
else
{
Primary.appendText(s);
}
}
//formatting block
else
{
while(index < s.length()) //change this
{
if((index == characterCapacity) && (index < s.length() - 1))
{
while(s.charAt(index) != ' ')
{
index--;
}
String n = s.substring(0, index);
s = s.substring(index);
//if(n.charAt(n.length() - 1) == '\n')
//{
// Primary.appendText(n);
//}
//else
//{
Primary.appendText(n + "\n");
//}
index = 0;
}
else if((index == s.length() - 1) && (index <= characterCapacity) && (s.length() > 0))
{
Primary.appendText(s + "\n");
index = s.length(); //OR use break;
endOfPara = true;
Primary.forward();
Primary.deletePreviousChar();
}
else
{
index++;
}
/*if(charCounter > 90)
{
if((charCounter >= 90) && (s.charAt(index) != )
{
}
if(index == (s.length() - 1))
{
}
else
{
charCounter++;
}
}*/
}
/*if(endOfPara == true)
{
if(s.charAt(index - 2) != '\n')
{
Primary.appendText("\n");
}
}
endOfPara = false;*/
}
}
}
catch(Exception e)
{}
I had a previous version of this which worked A LOT better, but unfortunately, it would insert newline characters in the middle of words, in some cases.
So yeah, in a nutshell, this is why I want to use a third party library to "get row number"/"get total rows", or find some way to do it using textarea skin.
Please Help! I am really stuck on this...
Related
I am trying to write a program that will allows users to make short blog entries by typing abbreviations for common words. On completion of the input, Program will expand the abbreviations according to the lexicon defined.
Conditions
A substituted word must be the shortest word that can be formed by adding zero or more letters (or punctuation symbols) to the abbreviation.
If two or more unique words can be formed by adding the same number of letters, then the abbreviation should be printed as it is.
Input
The input is divided into two sections.
The first section is the lexicon itself, and the second section is a user's blog entry that needs to be expanded. The sections are divided by a single | character.
For example:-
cream chocolate every ever does do ice is fried friend friends lick like floor favor flavor flower best but probably poorly say says that what white our you your strawberry storyboard the | wht flvr ic crm ds yr bst fnd lke? ur frds lk stbry, bt choc s prly th bs flr vr!
Output
what flavor ice cream does your best friend like? our friends lk strawberry, but chocolate is poorly the best floor ever!
I have written the program for this and tested it locally with many different test cases with success but it fails on submission to test server.
An automated Test suit runs to validate the program’s output on its submission to test server. In case of failure, details of the failing test case/cases are not visible.
Below is the program
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class BlogEntry {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String[][] info = readInput();
String[] output = inputExpander(info[0],info[1]);
//System.out.println();
for(int i = 0; i < output.length; ++i) {
if(i!=0)
System.out.print(" ");
System.out.print(output[i]);
}
}
public static String[][] readInput() {
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(
System.in));
String input = null;
String[][] info = new String[2][];
String[] text;
String[] abbr;
try {
input = bufferReader.readLine();
StringTokenizer st1 = new StringTokenizer(input, "|");
String first = "", second = "";
int count = 0;
while (st1.hasMoreTokens()) {
++count;
if(count == 1)
first = st1.nextToken();
if(count == 2)
second = st1.nextToken();
}
st1 = new StringTokenizer(first, " ");
count = st1.countTokens();
text = new String[count];
count = 0;
while (st1.hasMoreTokens()) {
text[count] = st1.nextToken();
count++;
}
st1 = new StringTokenizer(second, " ");
count = st1.countTokens();
abbr = new String[count];
count = 0;
while (st1.hasMoreTokens()) {
abbr[count] = st1.nextToken();
count++;
}
info[0] = text;
info[1] = abbr;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return info;
}
public static String[] inputExpander(String[] text, String[] abbr) {
String[] output = new String[abbr.length];
boolean result;
for (int i = 0; i < abbr.length; ++i) {
String abbrToken = abbr[i];
char[] char_abbr_token = abbrToken.toCharArray();
for (int j = 0; j < text.length; ++j) {
String textToken = text[j];
boolean flag2 = false;
if ((char_abbr_token[char_abbr_token.length - 1] == '!')
|| (char_abbr_token[char_abbr_token.length - 1] == '?')
|| (char_abbr_token[char_abbr_token.length - 1] == ',')
|| (char_abbr_token[char_abbr_token.length - 1] == ';')) {
flag2 = true;
}
char[] char_text_token = textToken.toCharArray();
result = ifcontains(char_text_token, char_abbr_token);
if (result) {
int currentCount = textToken.length();
int alreadyStoredCount = 0;
if (flag2)
textToken = textToken
+ char_abbr_token[char_abbr_token.length - 1];
if (output[i] == null)
output[i] = textToken;
else {
alreadyStoredCount = output[i].length();
char[] char_stored_token = output[i].toCharArray();
if ((char_stored_token[char_stored_token.length - 1] == '!')
|| (char_stored_token[char_stored_token.length - 1] == '?')
|| (char_stored_token[char_stored_token.length - 1] == ',')
|| (char_stored_token[char_stored_token.length - 1] == ';')) {
alreadyStoredCount -= 1;
}
if (alreadyStoredCount > currentCount) {
output[i] = textToken;
} else if (alreadyStoredCount == currentCount) {
output[i] = abbrToken;
}
}
}
}
if(output[i] == null)
output[i] = abbrToken;
}
return output;
}
public static boolean ifcontains(char[] char_text_token,
char[] char_abbr_token) {
int j = 0;
boolean flag = false;
for (int i = 0; i < char_abbr_token.length; ++i) {
flag = false;
for (; j < char_text_token.length; ++j) {
if ((char_abbr_token[i] == '!') || (char_abbr_token[i] == '?')
|| (char_abbr_token[i] == ',')
|| (char_abbr_token[i] == ';')) {
flag = true;
break;
}
if (char_abbr_token[i] == char_text_token[j]) {
flag = true;
break;
}
}
if (!flag)
return flag;
}
//System.out.println("match found" + flag);
return flag;
}
}
Can someone direct/hint me to/about the possible use case which I may have missed in the implementation? Thanks in advance.
Ran your program with duplicate word in input (lexicon). When a word is repeated in the lexicon, it is not getting expanded because the check is only on the length(line no. 112) of the stored word not its content.
I think you need to check:-
If same word appears more than once then expand.
If 2 or more unique words of same length appear then keep it short.
How would I approach solving this:
Parse the input, tokenize the lexicon and the text.
For each (possibly abbreviated) token like choc convert it to a regular expression like .*c.*h.*o.*c.*.
Search for shortest lexicon words matching this regular expression. Replace the text token if exactly one is found, otherwise leave it alone.
It is quite hard to say what's wrong with your code without careful debugging. It is hard to understand what one or the other part of the code does, it's not quite self-evident.
I'm trying to make a console formatter for my application and so far I've made it! But there are two big problems that I want to fix.
First: how do I handle the \n char in it?
and Second: Why it prints the text 'randomly'?
So this is my code:
public synchronized void formattedLog(PrintStream stream, String message, String prefix, int consoleWidth, int fontWidth) {
int maxCharsOnOneLine = consoleWidth / fontWidth;
int maxCharsWithPrefix = maxCharsOnOneLine - prefix.length();
StringBuilder builder = new StringBuilder();
String toAppend = "";
int charAt = 0;
while (true) {
String word = "";
int charWordIndex = charAt + 1;
if (message.charAt(charAt) == ' ' || charAt == 0) {
if (charAt == 0) {
word += message.charAt(0);
}
while (charWordIndex < message.length()) {
char nextChar = message.charAt(charWordIndex);
if (nextChar != ' ' && nextChar != '\n') {
word += nextChar;
} else {
break;
}
charWordIndex++;
}
}
if (word != "") {
if (word.length() <= maxCharsWithPrefix) {
if ((toAppend + word).length() <= maxCharsWithPrefix) {
toAppend += word + " ";
} else {
builder.append(prefix);
builder.append(toAppend);
builder.append("\n");
toAppend = "";
toAppend += word + " ";
}
} else {
int wordChar = 0;
toAppend += "";
while (true) {
if (toAppend.length() < maxCharsWithPrefix) {
if (wordChar < word.length()) toAppend += word.charAt(wordChar);
} else {
builder.append(prefix);
builder.append(toAppend);
builder.append("\n");
toAppend = "";
toAppend += word.charAt(wordChar);
}
wordChar++;
if (wordChar >= word.length()) {
toAppend += " ";
break;
}
}
}
}
charAt++;
if (charAt >= message.length()) {
builder.append(prefix);
builder.append(toAppend);
builder.append("\n");
break;
}
}
stream.println(builder.toString());
}
First: Now it does not 'parse' the strings with \n in it, but if it would it would look like this:
LOG> Text (\n)
Other text
LOG> ...
And I don't want that. I want it to print
LOG> Text (\n)
LOG> Other Text
LOG> ...
How could I achieve this?
And second by random I mean this:
I have this simple code to try the thing out; here it is:
public static void main(String[] args) {
//executorService = Executors.newFixedThreadPool(10);
consoleFormatter = new ConsoleFormatter();
consoleFormatter.logDefault("This is a long text to try the functionality of the method. This is literally ", "LOG> ", 600);
consoleFormatter.logDefault("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee test words words words", "LOG> ", 200);
try {
throwFakeExecption(new NullPointerException("Fake null pointer exception."));
} catch (Exception e) {
consoleFormatter.logError(e.toString(), "ERROR> ", 1000);
consoleFormatter.logError(e.getStackTrace()[0].toString(), "ERROR> ", 1000);
}
}
public static void throwFakeExecption(Exception ex) throws Exception {
throw ex;
}
Sometimes it prints it like this:
Other times like this:
And even other times like this:
I want the text to be in order and I don't know why it is doing that.
How could I fix these two problems?
I am having the following string and want to track the closing bracket of ROUND( ) in my string.
"=ROUND(IF(AND($BY18=2);CA18*CB18/$M$11;IF($BY18=3;CA18*CB18/$M$10;IF($BY18=4;ROUND(CA18*CB18;$M$10)/$M$9;CA18*CB18)))/$M$12;$M$11)";
public class RoundParser {
public static String parseRound(String text) {
text = text.toUpperCase();
String result;
char[] ch = text.toCharArray();
int count = -1;
String temp = "";
for (int i = 0; i < ch.length; i++) {
temp = temp + ch[i];
System.out.println(count);
if ("ROUND(".equals(temp)) {
count++;
}
if ("(".equals(temp)) {
count++;
}
if (")".equals(temp) && count > 0) {
count--;
}
if (")".equals(temp) && count == 0) {
ch[i] = '#';
}
if (!"ROUND(".startsWith(temp) || temp.length() > 5) {
temp = "";
}
}
text = String.valueOf(ch);
result = text;
return result;
}
public static void main(String[] args) {
String text = "=ROUND(IF(AND($BY18=2);CA18*CB18/$M$11;IF($BY18=3;CA18*CB18/$M$10;IF($BY18=4;ROUND(CA18*CB18;$M$10)/$M$9;CA18*CB18)))/$M$12;$M$11)";
System.out.println(parseRound(text));
}
}
However, using my parser at the moment I am getting:
=ROUND(IF(AND($BY18=2);CA18*CB18/$M$11;IF($BY18=3;CA18*CB18/$M$10;IF($BY18=4;ROUND(CA18*CB18;$M$10)/$M$9;CA18*CB18))#/$M$12;$M$11#
The output I want to get is:
=ROUND(IF(AND($BY18=2);CA18*CB18/$M$11;IF($BY18=3;CA18*CB18/$M$10;IF($BY18=4;ROUND(CA18*CB18;$M$10#/$M$9;CA18*CB18)))/$M$12;$M$11#
As you can see the not the right ) are replaced, as ;$M$11)"; and ;$M$10). I really appreciate if you have any idea how to repalce these two cases.
there are 2 approaches to this
1) if the number of opening and closing brackets are always going to be equal, then you can just track the last closing bracket by using a for loop.
2) if you are not sure about opening and closing brackets to be equal, then you can so the following-->
public class RoundParser {
public static String parseRound(String text) {
text = text.toUpperCase();
String result;
char[] ch = text.toCharArray();
int count=0,pos=0;
int c[10];
for(int i=0;i<ch.length;i++){
if(ch[i].equals("(")){
count++;
if(ch[i-1].equals("D")){
c[pos]=count; //will store the count value at every opening round
pos++;
}
}
if(ch[i].equals(")")){
count--;
for(int j=0;j<10;j++){
if(c[j]==count) //if the closing of round had been encountered
ch[i]="#";
}
}
}
text = String.valueOf(ch);
result = text;
return result;
}
public static void main(String[] args) {
String text = "=ROUND(IF(AND($BY18=2);CA18*CB18/$M$11;IF($BY18=3;CA18*CB18/$M$10;IF($BY18=4;ROUND(CA18*CB18;$M$10)/$M$9;CA18*CB18)))/$M$12;$M$11)";
System.out.println(parseRound(text));
}
}
there you go.
i think this should work.
hope this helps.
You forgot an else:
else if (")".equals(temp) && count == 0) {
That will decrement count and if then count==0, it will decrement twice.
This problem can be done recursively.
First, you use method .indexOf("ROUND(") to detect the first occurrence of round().
Then, we need to determine which is the end ')' of this round(). A simple algo will be enough :
int start = text.indexOf("ROUND(") + "ROUND(".length();
int count = 1;
int end = -1;
for(int i = start; i < text.length; i++){
if(text.charAt(i) == '('){
count++;
}else if(text.charAt(i) == ')'){
count--;
}
if(count == 0){
end = i;
break;
}
}
After you detect the start and end of the outer round(), you can use text.substring(start, end) to remove the outer round(), and continue the above function recursively, until you find all round()
For recognition of multiple ROUND(X), I suggest
TreeMap<Integer,Pair<Integer,Integer>> map = new TreeMap<>();
int count = 0;
Where we store <start_index, <init_count, end_index>>
if ("ROUND(".equals(temp))
{
map.put(i, new Pair<Integer,Integer>(count, -1));
count++;
}
if ("(".equals(temp)) count++;
if (")".equals(temp))
{
if (count <= 0)
{
count = 0;
// Error: extra closing bracket
}
else
{
count--;
}
int max_i = -1;
for (Integer index : map.keySet())
{
if (index > max_i
&& map.get(index).second() == -1
&& map.get(index).first() == count)
{
max_i = index;
}
}
if (max_i > -1) map.get(max_i).setSecond(i);
}
Here's an algorithm..
If you are not sure that the last ")" would be the one you are looking for.
Start from index 0 of the String, for each "(" you encounter, increment the count, and for each ")" decrement the count, replace the ")" with "#".
I would like to check if a semicolon (;) is in the brackets of an AND or OR block within a string.
For example:
IF(AND(ROUND($GX18-SUM(0)/$M$12;2)<=0;$AK$7=1);0;OR(1;A2)+O2)
If it's not within an AND or OR then I replace it with #:
IF(AND(ROUND($GX18-SUM(0)/$M$12;2)<=0$AK$7=1)#0#OR(1;A2)+O2)
I know how to do the substitution, but how do I detect whether the ; is inside such a block?
UPDATE
Using regex possibly seems quite complex. However, to break down the problem:
How to detect if a certain char(;) is within an AND(...) or OR(...)? This would help me a lot!
Hope following java code helps to resolve your problem,
String str = "IF(AND(ROUND($GX18-SUM(0)/$M$12;2)<=0$AK$7=1);0;OR(1;A2)+O2)";
char[] ch = str.toCharArray();
int count = 0;
String temp = "";
for (int i = 0; i < ch.length; i++) {
temp = temp + ch[i];
if ("AND(".equals(temp) || "OR(".equals(temp)) {
count++;
}
if ("(".equals(temp) && count > 0) {
count++;
}
if (")".equals(temp) && count > 0) {
count--;
}
if (";".equals(temp) && count == 0) {
ch[i] = '#';
}
if ((!"AND(".startsWith(temp) && !"OR(".startsWith(temp)) || temp.length() > 4) {
temp = "";
}
}
System.out.println("Expected Data >> " + String.valueOf(ch));
I am trying to get user input for sortValues[] array using the for statement (enter character 1, enter character 2, etc).
However, when I execute this, the program will not allow me to enter for character 2, instead skipping directly to character 3, as seen below.
How to resolve this? The code is included below.
thanks!
static public void s_1d_char () {
int counter=0;
int x=0;
c.print("How many characters? ");
counter = readInt();
char[] sortValues = new char[counter+1];
for (x=1;x<=counter;x++) {
System.out.println("Enter character "+(x)+":");
sortValues[x] = readChar();
}
}
readChar implementation (this is from a library):
public synchronized char readChar ()
{
char result, ch;
if (ungotChar != EMPTY_BUFFER)
{
result = (char) ungotChar;
ungotChar = EMPTY_BUFFER;
return (result);
}
if (lineBufferHead != lineBufferTail)
{
result = lineBuffer [lineBufferTail];
lineBufferTail = (lineBufferTail + 1) % lineBuffer.length;
return (result);
}
startRow = currentRow;
startCol = currentCol;
if (currentRow > maxRow)
{
startRow++;
currentCol = 1;
}
// Turn cursor on if necessary
consoleCanvas.setCursorVisible (true);
// Wait for a character to be entered
while (true)
{
ch = getChar ();
if (ch == '\n')
{
clearToEOL = false;
if (echoOn)
print ("\n");
clearToEOL = true;
lineBuffer [lineBufferHead] = '\n';
lineBufferHead = (lineBufferHead + 1) % lineBuffer.length;
break;
}
if (ch == '\b')
{
if (lineBufferHead == lineBufferTail)
{
consoleCanvas.invertScreen ();
}
else
{
int chToErase;
lineBufferHead = (lineBufferHead + lineBuffer.length - 1) % lineBuffer.length;
chToErase = lineBuffer [lineBufferHead];
if (echoOn)
{
if (chToErase != '\t')
{
erasePreviousChar ();
}
else
{
int cnt;
eraseLineOfInput ();
cnt = lineBufferTail;
while (cnt != lineBufferHead)
{
print (lineBuffer [cnt]);
cnt = (cnt + 1) % lineBuffer.length;
}
}
}
}
} // if backspace
else if (ch == '\025')
{
if (echoOn)
{
eraseLineOfInput ();
}
lineBufferHead = lineBufferTail;
}
else
{
if (echoOn)
{
print (ch);
}
lineBuffer [lineBufferHead] = ch;
lineBufferHead = (lineBufferHead + 1) % lineBuffer.length;
}
} // while
result = lineBuffer [lineBufferTail];
lineBufferTail = (lineBufferTail + 1) % lineBuffer.length;
// Turn cursor on if necessary
consoleCanvas.setCursorVisible (false);
return (result);
}
I recommend getting user input with a scanner:
import java.util.Scanner;
// ...
int counter = 0;
System.out.println("How many characters?");
Scanner keyboard = new Scanner(System.in);
counter = keyboard.nextInt();
char[] sortValues = new char[counter+1];
// Start your index variable off at 0
for (int x = 0; x < counter; x++) {
System.out.println("Enter character "+(x)+":");
keyboard = new Scanner(System.in);
String line = keyboard.nextLine();
sortValues[x] = line.charAt(0);
}
This will capture the first character of the line. If the user enters more than one character, the program will read only the first.
Also, you should really start your index variable x off at 0, considering arrays are 0-based indexed.
instead of readChar() try:
sortValues[x] = Integer.parseInt(System.console().readLine());
How to read integer value from the standard input in Java