JavaME is quite sparse on features. Please list your favourite utility functions for making using it more like using proper Java, one per answer. Try to make your answers specific to Java ME.
Small Logging Framework
MicroLog
http://microlog.sourceforge.net/site/
Splitting a string
static public String[] split(String str, char c)
{
int l=str.length();
int count = 0;
for(int i = 0;i < l;i++)
{
if (str.charAt(i) == c)
{
count ++;
}
}
int first = 0;
int last = 0;
int segment=0;
String[] array = new String[count + 1];
for(int i=0;i<l;i++)
{
if (str.charAt(i) == c)
{
last = i;
array[segment++] = str.substring(first,last);
first = last;
}
if(i==l-1){
array[segment++] = str.substring(first,l);
}
}
return array;
}
Read a line from a reader. See also this question.
public class LineReader{
private Reader in;
private int bucket=-1;
public LineReader(Reader in){
this.in=in;
}
public boolean hasLine() throws IOException{
if(bucket!=-1)return true;
bucket=in.read();
return bucket!=-1;
}
//Read a line, removing any /r and /n. Buffers the string
public String readLine() throws IOException{
int tmp;
StringBuffer out=new StringBuffer();
//Read in data
while(true){
//Check the bucket first. If empty read from the input stream
if(bucket!=-1){
tmp=bucket;
bucket=-1;
}else{
tmp=in.read();
if(tmp==-1)break;
}
//If new line, then discard it. If we get a \r, we need to look ahead so can use bucket
if(tmp=='\r'){
int nextChar=in.read();
if(tmp!='\n')bucket=nextChar;//Ignores \r\n, but not \r\r
break;
}else if(tmp=='\n'){
break;
}else{
//Otherwise just append the character
out.append((char) tmp);
}
}
return out.toString();
}
}
Related
I have coded the following solution, and it works, except for when there is punctuation. I was wondering if there are O(1) space complexity and O(length of string) time complexity solutions, without using reverse() method, or anything similar that makes this task too easy. Any answer that can also handle punctuation correctly would be great.
Example:
Given string: "I love chocolate"
Return string should be: "I evol etalocohc"
For clarity, when I say handle punctuation correctly, I mean punctuation should not move around.
// reverse the letters of every word in a sentence (string), and return the result
public static String reverse(String x)
{
String[] str = x.split(" ");
StringBuilder rev = new StringBuilder("");
for (int i = 0; i < str.length; i++)
{
for (int s = str[i].length()-1; s >= 0; s--)
{
rev.append(str[i].charAt(s));
}
rev.append(" ");
}
return rev.toString();
}
Here is my output for some tests of mine:
public static void main(String[] args)
{
System.out.println(reverse("I love chocolate"));//this passes
System.out.println(reverse("Geeks for Geeks"));//this passes
System.out.println(reverse("You, are awesome"));//not handling puncutation mark correctly, gives me ",uoY era emosewa", instead of "uoY, era emosewa"
System.out.println(reverse("Geeks! for Geeks."));//not handling puncutation marks correctly, gives me "!skeeG rof .skeeG", instead of "skeeG! rof skeeG."
}
This would probably work with the punctuation:
public static String reverse(String x)
{
String[] str = x.split("\\W"); //Split on non-word characters.
StringBuilder rev = new StringBuilder("");
int currentPosition = 0;
for (int i = 0; i < str.length; i++)
{
for (int s = str[i].length()-1; s >= 0; s--)
{
rev.append(str[i].charAt(s));
currentPosition++;
}
while (currentPosition < x.length() && Character.toString(x.charAt(currentPosition)).matches("\\W"))
rev.append(x.charAt(currentPosition++)); //Add the actual character there.
}
return rev.toString();
}
Haven't coded in Java in a while now so I know it's probably not best practices here.
Complexity is O(n) (space and time).
If you start off with a string builder you might be able to lower space complexity by using in-place character swaps instead of appending, but you'd need to preemptively find where all the non-word characters are.
Here is an implementation which uses in-place reversing of words requiring only O(1) storage. In addition, the reversing algorithm itself is O(N) with the length of the string.
The basic algorithm is to walk down the string until hitting a space. Then, the swap() method is called to reverse that particular word in place. It only needs at any moment one extra character.
This approach may not be as performant as the accepted answer due to its heavy use of StringBuilder manipulations. But this might something to consider in an environment like an Android application where space is very precious.
public static void swap(StringBuilder input, int start, int end) {
for (int i=0; i <= (end - start) / 2; ++i) {
char ch = input.charAt(start + i);
input.setCharAt(start + i, input.charAt(end - i));
input.setCharAt(end - i, ch);
}
}
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("I love chocolate");
int start = 0;
int end = 0;
while (true) {
while (end <= sb.length() - 1 && sb.charAt(end) != ' ') {
++end;
}
swap(sb, start, end - 1);
start = end + 1;
end = start;
if (end > sb.length() - 1) {
break;
}
}
System.out.println(sb);
}
Demo here:
Rextester
A compact solution is
public static String reverse(String x) {
Matcher m = Pattern.compile("\\w+").matcher(x);
if(!m.find()) return x;
StringBuffer target = new StringBuffer(x.length());
do m.appendReplacement(target, new StringBuilder(m.group()).reverse().toString());
while(m.find());
return m.appendTail(target).toString();
}
The appendReplacement loop + appendTail on a Matcher is the manual equivalent of String.replaceAll(regex), intended to support exactly such cases where the replacement is more complex than a simple string with placeholders, like reversing the found words.
Unfortunately, we have to use the outdated StringBuffer here, as the API is older than StringBuilder. Java 9 is going to change that.
A potentially more efficient alternative is
public static String reverse(String x) {
Matcher m = Pattern.compile("\\w+").matcher(x);
if(!m.find()) return x;
StringBuilder target = new StringBuilder(x.length());
int last=0;
do {
int s = m.start(), e = m.end();
target.append(x, last, s).append(new StringBuilder(e-s).append(x, s, e).reverse());
last = e;
}
while(m.find());
return target.append(x, last, x.length()).toString();
}
This uses StringBuilder throughout the operation and usese the feature to append partial character sequences, not creating intermediate strings for the match and replacement. It also elides the search for placeholders in the replacement, which appendReplacement does internally.
I just have made changes on your code, not additional methods or loops, just some variables and if conditions.
/* Soner - The methods reverse a string with preserving punctiations */
public static String reverse(String x) {
String[] str = x.split(" ");
boolean flag = false;
int lastCharPosition;
StringBuilder rev = new StringBuilder("");
for (int i = 0; i < str.length; i++) {
flag = false;
lastCharPosition = str[i].length()-1;
if (str[i].charAt(lastCharPosition) == '.' || str[i].charAt(lastCharPosition) == '!'
|| str[i].charAt(lastCharPosition) == ',') { // you can add new punctiations
flag = true;
lastCharPosition = str[i].length()-2;
}
for (int s = lastCharPosition; s >= 0; s--) {
rev.append(str[i].charAt(s));
}
if (flag) rev.append(str[i].charAt(lastCharPosition + 1));
rev.append(" ");
}
return rev.toString();
}
The code below is giving me the error java.util.NoSuchElementException right after I Ctrl+Z
to indicate that the user input is complete. By the looks of it seems as if it does not know how to just end one method without messing with the other scanner object.
I try the hasNext method and I ended up with an infinite loop, either way is not working. As a requirement for this assignment I need to be able to tell the user to use Ctrl+Z or D depending on the operating system. Also I need to be able to read from a text file and save the final tree to a text file please help.
/* sample input:
CSCI3320
project
personal
1 HW1
1 HW2
1 2 MSS.java
2 p1.java
*/
import java.util.Scanner;
import java.util.StringTokenizer;
public class Directory {
private static TreeNode root = new TreeNode("/", null, null);
public static void main(String[] args) {
userMenu();
System.out.println("The directory is displayed as follows:");
root.listAll(0);
}
private static void userMenu(){ //Displays users menu
Scanner userInput = new Scanner(System.in);//Scanner option
int option = 0;
do{ //I believe the problem is here since I am not using userInput.Next()
System.out.println("\n 1. add files from user inputs ");
System.out.println("\n 2. display the whole directory ");
System.out.println("\n 3. display the size of directory ");
System.out.println("\n 0. exit");
System.out.println("\n Please give a selection [0-3]: ");
option = userInput.nextInt();
switch(option){
case 1: addFileFromUser();
break;
case 2: System.out.println("The directory is displayed as follows:");
root.listAll(0);
break;
case 3: System.out.printf("The size of the directory is %d.\n", root.size());
break;
default:
break;
}
}while( option !=0);
userInput.close();
}
private static void addFileFromUser() {
System.out.println("To terminate inp1ut, type the correct end-of-file indicator ");
System.out.println("when you are prompted to enter input.");
System.out.println("On UNIX/Linux/Mac OS X type <ctrl> d");
System.out.println("On Windows type <ctrl> z");
Scanner input = new Scanner(System.in);
while (input.hasNext()) { //hasNext being used Crtl Z is required to break
addFileIntoDirectory(input); // out of the loop.
}
input.close();
}
private static void addFileIntoDirectory(Scanner input) {
String line = input.nextLine();
if (line.trim().equals("")) return;
StringTokenizer tokens = new StringTokenizer(line);
int n = tokens.countTokens() - 1;
TreeNode p = root;
while (n > 0 && p.isDirectory()) {
int a = Integer.valueOf( tokens.nextToken() );
p = p.getFirstChild();
while (a > 1 && p != null) {
p = p.getNextSibling();
a--;
}
n--;
}
String name = tokens.nextToken();
TreeNode newNode = new TreeNode(name, null, null);
if (p.getFirstChild() == null) {
p.setFirstChild(newNode);
}
else {
p = p.getFirstChild();
while (p.getNextSibling() != null) {
p = p.getNextSibling();
}
p.setNextSibling(newNode);
}
}
private static class TreeNode {
private String element;
private TreeNode firstChild;
private TreeNode nextSibling;
public TreeNode(String e, TreeNode f, TreeNode s) {
setElement(e);
setFirstChild(f);
setNextSibling(s);
}
public void listAll(int i) {
for (int k = 0; k < i; k++) {
System.out.print('\t');
}
System.out.println(getElement());
if (isDirectory()) {
TreeNode t = getFirstChild();
while (t != null) {
t.listAll(i+1);
t = t.getNextSibling();
}
}
}
public int size() {
int s = 1;
if (isDirectory()) {
TreeNode t = getFirstChild();
while (t != null) {
s += t.size();
t = t.getNextSibling();
}
}
return s;
}
public void setElement(String e) {
element = e;
}
public String getElement() {
return element;
}
public boolean isDirectory() {
return getFirstChild() != null;
}
public void setFirstChild(TreeNode f) {
firstChild = f;
}
public TreeNode getFirstChild() {
return firstChild;
}
public void setNextSibling(TreeNode s) {
nextSibling = s;
}
public TreeNode getNextSibling() {
return nextSibling;
}
}
}
Exception Details:
/*Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:907)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at Directory.userMenu(Directory.java:36)
at Directory.main(Directory.java:21)*/
Your problem is this line:
option = userInput.nextInt(); //line 24
If you read the Javadoc, you will find that the nextInt() method can throw a NoSuchElementException if the input is exhausted. In other words, there is no next integer to get. Why is this happening in your code? Because you this line is in a loop once that first iteration completes (on the outer while loop) your initial input selection has been consumed. Since this is a homework, I am not going to write the code. But, if you remove the loop, you know this works at least once. Once you try to loop, it breaks. So I will give you these hints:
Change the do/while to a while loop.
Prompt the user once outside the loop.
Recreate the prompt and recapture the user input inside the loop.
For example, the code below can be used for the basis of your outer loop.
import java.util.Scanner;
public class GuessNumberGame {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Guess the secret number: (Hint: the secret number is 1)");
int guess = input.nextInt();
while (guess != 1) {
System.out.println("Wrong guess. Try again: ");
guess = input.nextInt();
}
System.out.println("Success");
input.close();
}
}
The reason why this works is because I don't reuse the same, exhausted, scanner input object to get the next integer. In your example, the initial input is inside the loop. The second time around, that input has already been consumed. Follow this pattern and you should be able to complete your assignment.
Whenever I run this code, it works pretty smoothly, until the while loop runs through once. It will go back and ask for the name again, and then skip String b = sc.nextLine();, and print the next line, instead.
static Scanner sc = new Scanner(System.in);
static public void main(String [] argv) {
Name();
}
static public void Name() {
boolean again = false;
do
{
System.out.println("What is your name?");
String b = sc.nextLine();
System.out.println("Ah, so your name is " + b +"?\n" +
"(y//n)");
int a = getYN();
System.out.println(a + "! Good.");
again = askQuestion();
} while(again);
}
static public boolean askQuestion() {
System.out.println("Do you want to try again?");
int answer = sc.nextInt();
if (answer == 1) {
return true;
}
else {
return false;
}
}
static int getYN() {
switch (sc.nextLine().substring(0, 1).toLowerCase()) {
case "y":
return 1;
case "n":
return 0;
default:
return 2;
}
}
}
Also, I'm trying to create this program in a way that I can ask three questions (like someone's Name, Gender, and Age, maybe more like race and whatnot), and then bring all of those answers back. Like, at the very end, say, "So, your name is + name +, you are + gender +, and you are + age + years old? Yes/No." Something along those lines. I know there's a way to do it, but I don't know how to save those responses anywhere, and I can't grab them since they only occur in the instance of the method.
Don't try to scan text with nextLine() AFTER using nextInt() with the same scanner! It may cause problems. Open a scanner method for ints only...it's recommended.
You could always parse the String answer of the scanner.
Also, using scanner this way is not a good practice, you could organize questions in array an choose a loop reading for a unique scanner instantiation like this:
public class a {
private static String InputName;
private static String Sex;
private static String Age;
private static String input;
static Scanner sc ;
static public void main(String [] argv) {
Name();
}
static public void Name() {
sc = new Scanner(System.in);
String[] questions = {"Name?","Age","Sex?"};//
int a = 0;
System.out.println(questions[a]);
while (sc.hasNext()) {
input = sc.next();
setVariable(a, input);
if(input.equalsIgnoreCase("no")){
sc.close();
break;
}
else if(a>questions.length -1)
{
a = 0;
}
else{
a++;
}
if(a>questions.length -1){
System.out.println("Fine " + InputName
+ " so you are " + Age + " years old and " + Sex + "." );
Age = null;
Sex = null;
InputName = null;
System.out.println("Loop again?");
}
if(!input.equalsIgnoreCase("no") && a<questions.length){
System.out.println(questions[a]);
}
}
}
static void setVariable(int a, String Field) {
switch (a) {
case 0:
InputName = Field;
return;
case 1:
Age = Field;
return;
case 2:
Sex = Field;
return;
}
}
}
Pay attention on the global variables, wich stores your info until you set them null or empty...you could use them to the final affirmation.
Hope this helps!
Hope this helps!
I see that you can't use string tokenizer on an array because you cant convert String() to String[]. After a length of time I realized that if the inputFromFile method reads it line by line, I can tokenize it line by line. I just don't know how to do it so that it returns the tokenized version of it.
I'm assuming in the line=in.ReadLine(); line I should put StringTokenizer token = new StringTokenizer(line,",").. but it doesn't seem to be working.
Any help? (I have to tokenize the commas).
public class Project1 {
private static int inputFromFile(String filename, String[] wordArray) {
TextFileInput in = new TextFileInput(filename);
int lengthFilled = 0;
String line = in.readLine();
while (lengthFilled < wordArray.length && line != null) {
wordArray[lengthFilled++] = line;
line = in.readLine();
}// while
if (line != null) {
System.out.println("File contains too many Strings.");
System.out.println("This program can process only "
+ wordArray.length + " Strings.");
System.exit(1);
} // if
in.close();
return lengthFilled;
} // method inputFromFile
public static void main(String[] args) {
String[] numArray = new String[100];
inputFromFile("input1.txt", numArray);
for (int i = 0; i < numArray.length; i++) {
if (numArray[i] == null) {
break;
}
System.out.println(numArray[i]);
}// for
for (int i=0;i<numArray.length;i++)
{
Integer.parseInt(numArray[i]);
}
}// main
}// project1
This is what I meant:
while (lengthFilled < wordArray.length && line != null) {
String[] tokens = line.split(",");
if(tokens == null || tokens.length == 0) {
//line without required token, add whole line as it is
wordArray[lengthFilled++] = line;
} else {
//add each token into wordArray
for(int i=0; i<tokens.length;i++) {
wordArray[lengthFilled++] = tokens[i];
}
}
line = in.readLine();
}// while
There can be other approaches as well. For instance, you can use a StringBuilder to read everything as one big string and them split it on your required tokens etc. The above logic is just to point you in right direction.
Could you please point out where is the bug in my code?
I have a simple text file with the following data structure:
something1
something2
something3
...
It results a String[] where every element is the last element of the file. I can't find the mistake, but it goes wrong somewhere around the line.setLength(0);
Any ideas?
public String[] readText() throws IOException {
InputStream file = getClass().getResourceAsStream("/questions.txt");
DataInputStream in = new DataInputStream(file);
StringBuffer line = new StringBuffer();
Vector lines = new Vector();
int c;
try {
while( ( c = in.read()) != -1 ) {
if ((char)c == '\n') {
if (line.length() > 0) {
// debug
//System.out.println(line.toString());
lines.addElement(line);
line.setLength(0);
}
}
else{
line.append((char)c);
}
}
if(line.length() > 0){
lines.addElement(line);
line.setLength(0);
}
String[] splitArray = new String[lines.size()];
for (int i = 0; i < splitArray.length; i++) {
splitArray[i] = lines.elementAt(i).toString();
}
return splitArray;
} catch(Exception e) {
System.out.println(e.getMessage());
return null;
} finally {
in.close();
}
}
I see one obvious error - you're storing the same StringBuffer instance multiple times in the Vector, and you clear the same StringBuffer instance with setLength(0). I'm guesing you want to do something like this
StringBuffer s = new StringBuffer();
Vector v = new Vector();
...
String bufferContents = s.toString();
v.addElement(bufferContents);
s.setLength(0);
// now it's ok to reuse s
...
If your problem is to read the contents of the file in a String[], then you could actually use apache common's FileUtil class and read in an array list and then convert to an array.
List<String> fileContentsInList = FileUtils.readLines(new File("filename"));
String[] fileContentsInArray = new String[fileContentsInList.size()];
fileContentsInArray = (String[]) fileContentsInList.toArray(fileContentsInArray);
In the code that you have specified, rather than setting length to 0, you can reinitialize the StringBuffer.