I implemented a counter method that returns always an incremented number. But the user can give wished format, 2 digits, 3 digits or whatever he wants.
The format is the standard String.format() type of String like %02d or %5d. When the maximum value is reached, the counter should be reset to 0.
How can I find out the max value that can be represented with the given format?
int counter = 0;
private String getCounter(String format){
if(counter >= getMaximum(format)){
counter = 0;
}
else {
counter++;
}
return String.format(format, counter);
}
private int getMaximum(String format){
//TODO ???
//Format can be %02d => should return 100
//Format can be %05d => should return 100000
}
Haven't validated this code, but something along the lines of this should work with erro checking in place
String str = fullresultText.replace ("%", "").replace("d", "");
maxVal = Math.pow (10, Integer.parseInt (str));
private int counter = 0;
private String getCounter(String format) {
counter = (counter + 1) % getMaximum(format);
return String.format(format, counter);
}
private int getMaximum(String format) {
try {
MessageFormat messageFormat = new MessageFormat("%{0,number,integer}d");
int pow = ((Long) messageFormat.parse(format)[0]).intValue();
return (int) Math.pow(10, pow);
} catch (ParseException e) {
System.out.println("Incorrect format");
return -1;
}
}
There is nothing builtin for this, and I'm not aware of any libraries that do this (I could be wrong). Remember that formats will expand if necessary to avoid losing digits. For example
System.out.printf("%06d", 11434235);
will happily print the entire 8-digit number.
So specifying the format directly is probably not the right approach. Create a Counter class to encapsulate the desired "odometer" behavior.
public class Counter {
private int width;
private int limit;
private String format;
private int value=0;
public Counter(int width, int value) {
this.width = width;
this.limit = BigInteger.valueOf(10).pow(width).intValue()-1;
this.format = String.format("%%0%dd",width);
this.value = value;
}
public Counter(int width) {
this(width,0);
}
public Counter increment() {
value = value<limit ? value+1 : 0;
return this;
}
#Override
public String toString() {
return String.format(this.format,this.value);
}
}
Sample usage:
Counter c3 = new MiscTest.Counter(3,995);
for (int i=0; i<10; i++)
{
System.out.println(c3.increment().toString());
}
Output:
996
997
998
999
000
001
002
003
004
005
Related
This is a probable answer of my question in stack overflow.Integer to word conversion
At first I have started with dictionary. Then I came to know it is obsolete. So now I use Map instead of dictionary. My code is work well for number till Millions. But the approach I take here is a naive approach. The main problem of this code is
First: Huge numbers of variable use
2nd: Redundant code block as per program requirement
3rd: Multiple if else statement
I am thinking about this problems
Solution for 2nd problem: using user define function or macros to eliminate redundant code block
Solution for 3rd problem: Using switch case
My code:
public class IntegerEnglish {
public static void main(String args[]){
Scanner in=new Scanner(System.in);
System.out.println("Enter the integer");
int input_number=in.nextInt();
Map<Integer,String> numbers_converter = new HashMap<Integer,String>();
Map<Integer,String> number_place = new HashMap<Integer,String>();
Map<Integer,String> number_2nd = new HashMap<Integer,String>();
numbers_converter.put(0,"Zero");
numbers_converter.put(1,"One");
numbers_converter.put(2,"Two");
numbers_converter.put(3,"Three");
numbers_converter.put(4,"Four");
numbers_converter.put(5,"Five");
numbers_converter.put(6,"Six");
numbers_converter.put(7,"Seven");
numbers_converter.put(8,"Eight");
numbers_converter.put(9,"Nine");
numbers_converter.put(10,"Ten");
numbers_converter.put(11,"Eleven");
numbers_converter.put(12,"Twelve");
numbers_converter.put(13,"Thirteen");
numbers_converter.put(14,"Fourteen ");
numbers_converter.put(15,"Fifteen");
numbers_converter.put(16,"Sixteen");
numbers_converter.put(17,"Seventeen");
numbers_converter.put(18,"Eighteen");
numbers_converter.put(19,"Nineteen");
number_place.put(3,"Hundred");
number_place.put(4,"Thousand");
number_place.put(7,"Million");
number_place.put(11,"Billion");
number_2nd.put(2,"Twenty");
number_2nd.put(3,"Thirty");
number_2nd.put(4,"Forty");
number_2nd.put(5,"Fifty");
number_2nd.put(6,"Sixty");
number_2nd.put(7,"Seventy");
number_2nd.put(8,"Eighty");
number_2nd.put(9,"Ninty");
if(input_number== 0){
System.out.println("zero");
}
else if(input_number>0 && input_number<19){
System.out.println(numbers_converter.get(input_number));
}
else if(input_number>19 && input_number<100){
int rem=input_number%10;
input_number=input_number/10;
System.out.print(number_2nd.get(input_number));
System.out.print(numbers_converter.get(rem));
}
else if(input_number==100){
System.out.println(number_place.get(3));
}
else if(input_number>100 && input_number<1000){
int reminder=input_number%100;
int r1=reminder%10;
int q1=reminder/10;
int quot=input_number/100;
System.out.print(numbers_converter.get(quot) + "hundred");
if(reminder>0 && reminder<20){
System.out.print(numbers_converter.get(reminder));
}
else{
System.out.println(number_2nd.get(q1) + numbers_converter.get(r1));
}
}
else if(input_number==1000){
System.out.println(number_place.get(4));
}
else if(input_number>1000 && input_number<10000){
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
System.out.print(numbers_converter.get(thousand) + "thousand" + numbers_converter.get(hundred)+ " hundred");
if(rem >0 && rem<20){
System.out.print(numbers_converter.get(rem));
}
else if(rem >19 && rem <100){
System.out.print(number_2nd.get(quotient) + numbers_converter.get(rem_two));
}
}
else if(input_number>10000 && input_number<1000000000){
//Say number 418,229,356
int third_part=input_number%1000;//hold 356
input_number=input_number/1000;//hold 418,229
int sec_part=input_number%1000;//hold 229
input_number=input_number/1000;// hold 418
int rem_m=third_part%100;//hold 56
int rem_m1=rem_m%10;//hold 6
int rem_q=rem_m/10;// hold 5
int q_m=third_part/100;// hold 3
int sec_part_rem=sec_part%100;// hold 29
int sec_part_rem1=sec_part_rem%10;//9
int sec_part_q=sec_part_rem/10;//hold 2
int sec_q=sec_part/100;// hold 2
int input_q=input_number/100;// hold 4
int input_rem=input_number%100;//hold 18
int input_q_q=input_rem/10;//hold 1
int input_rem1=input_rem%10;// hold 8
System.out.print(numbers_converter.get(input_q) + " hundred ");
if(input_rem>0 && input_rem<20){
System.out.print(numbers_converter.get(input_rem)+ " Million ");
}
else{
System.out.print(number_2nd.get(input_q_q) + " " + numbers_converter.get(input_rem1) + " Million ");
}
System.out.print(numbers_converter.get(sec_q) + " hundred ");
if(sec_part_rem >0 && sec_part_rem<20){
System.out.println(numbers_converter.get(sec_part_rem) + " thousand ");
}
else{
System.out.print(number_2nd.get(sec_part_q) + " " + numbers_converter.get(sec_part_rem1) + " thousand ");
}
System.out.print(numbers_converter.get(q_m) + " hundred ");
if(rem_m>0 && rem_m<20){
System.out.print(numbers_converter.get(rem_m));
}
else{
System.out.print(number_2nd.get(rem_q) + " " + numbers_converter.get(rem_m1));
}
}
}
}
Redundant Code Blocks
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
This type of code block used almost every where. Taking a number divide it with 100 or 1000 to find out the hundred position then then divide it with 10 to find out the tenth position of the number. Finally using %(modular division) to find out the ones position.
How could I include user define function and switch case to minimize the code block.
Instead of storing the results in variables, use a method call:
int remainder100(int aNumber) {
return aNumber % 100;
}
int remainder10(int aNumber) {
return aNumber % 10;
}
...etc.
System.out.println(numbers_converter.get(remainder100(input_number)));
About 3rd problem: I wouldn't use switch ... case, too many cases.
Instead, take advantage that numbering repeats itself every 3 digits. That means the pattern for thousands and millions is the same (and billions, trillions, etc).
To do that, use a loop like this:
ArrayList<String> partialResult = new ArrayList<String>();
int powersOf1000 = 0;
for (int kiloCounter = input_number; kiloCounter > 0; kiloCounter /= 1000) {
partialResult.add(getThousandsMilionsBillionsEtc(powersOf1000++);
partialResult.add(convertThreeDigits(kiloCounter % 1000));
}
Then you can print out the contents of partialResult in reverse order to get the final number.
I'd suggest you break your single main method down into a couple of classes. And if you haven't already create a few unit tests to allow you to easily test / refactor things. You'll find it quicker than starting the app and reading from stdin.
You'll find it easier to deal with the number as a string. Rather than dividing by 10 all the time you just take the last character of the string. You could have a class that does that bit for you, and a separate one that does the convert.
Here's what I came up with, but I'm sure it can be improved. It has a PoppableNumber class which allows the last character of the initial number to be easily retrieved. And the NumberToString class which has a static convert method to perform the conversion.
An example of a test would be
#Test
public void Convert102356Test() {
assertEquals("one hundred and two thousand three hundred and fifty six", NumberToString.convert(102356));
}
And here's the NumberToString class :
import java.util.HashMap;
import java.util.Map;
public class NumberToString {
// billion is enough for an int, obviously need more for long
private static String[] power3 = new String[] {"", "thousand", "million", "billion"};
private static Map<String,String> numbers_below_twenty = new HashMap<String,String>();
private static Map<String,String> number_tens = new HashMap<String,String>();
static {
numbers_below_twenty.put("0","");
numbers_below_twenty.put("1","one");
numbers_below_twenty.put("2","two");
numbers_below_twenty.put("3","three");
numbers_below_twenty.put("4","four");
numbers_below_twenty.put("5","five");
numbers_below_twenty.put("6","six");
numbers_below_twenty.put("7","seven");
numbers_below_twenty.put("8","eight");
numbers_below_twenty.put("9","nine");
numbers_below_twenty.put("10","ten");
numbers_below_twenty.put("11","eleven");
numbers_below_twenty.put("12","twelve");
numbers_below_twenty.put("13","thirteen");
numbers_below_twenty.put("14","fourteen ");
numbers_below_twenty.put("15","fifteen");
numbers_below_twenty.put("16","sixteen");
numbers_below_twenty.put("17","seventeen");
numbers_below_twenty.put("18","eighteen");
numbers_below_twenty.put("19","nineteen");
number_tens.put(null,"");
number_tens.put("","");
number_tens.put("0","");
number_tens.put("2","twenty");
number_tens.put("3","thirty");
number_tens.put("4","forty");
number_tens.put("5","fifty");
number_tens.put("6","sixty");
number_tens.put("7","seventy");
number_tens.put("8","eighty");
number_tens.put("9","ninty");
}
public static String convert(int value) {
if (value == 0) {
return "zero";
}
PoppableNumber number = new PoppableNumber(value);
String result = "";
int power3Count = 0;
while (number.hasMore()) {
String nextPart = convertUnitTenHundred(number.pop(), number.pop(), number.pop());
nextPart = join(nextPart, " ", power3[power3Count++], true);
result = join(nextPart, " ", result);
}
if (number.isNegative()) {
result = join("minus", " ", result);
}
return result;
}
public static String convertUnitTenHundred(String units, String tens, String hundreds) {
String tens_and_units_part = "";
if (numbers_below_twenty.containsKey(tens+units)) {
tens_and_units_part = numbers_below_twenty.get(tens+units);
}
else {
tens_and_units_part = join(number_tens.get(tens), " ", numbers_below_twenty.get(units));
}
String hundred_part = join(numbers_below_twenty.get(hundreds), " ", "hundred", true);
return join(hundred_part, " and ", tens_and_units_part);
}
public static String join(String part1, String sep, String part2) {
return join(part1, sep, part2, false);
}
public static String join(String part1, String sep, String part2, boolean part1Required) {
if (part1 == null || part1.length() == 0) {
return (part1Required) ? "" : part2;
}
if (part2.length() == 0) {
return part1;
}
return part1 + sep + part2;
}
/**
*
* Convert an int to a string, and allow the last character to be taken off the string using pop() method.
*
* e.g.
* 1432
* Will give 2, then 3, then 4, and finally 1 on subsequent calls to pop().
*
* If there is nothing left, pop() will just return an empty string.
*
*/
static class PoppableNumber {
private int original;
private String number;
private int start;
private int next;
PoppableNumber(int value) {
this.original = value;
this.number = String.valueOf(value);
this.next = number.length();
this.start = (value < 0) ? 1 : 0; // allow for minus sign.
}
boolean isNegative() {
return (original < 0);
}
boolean hasMore() {
return (next > start);
}
String pop() {
return hasMore() ? number.substring(--next, next+1) : "";
}
}
}
public class aevi{
public static void main(String[] args) {
Scanner s=new Scanner(System.in);
long num=s.nextLong();
long i=0,j;
while(i<num)
{
long p=1,sum=0,reversesum=0;
j=num+i;
while(j>0)
{
System.out.print(j%2+" ");
sum+=(j%2)*p;
p=p*10;
j=j/2;
}
long r=sum;
System.out.print(r+" ");
while(sum!=0)
{
reversesum=(reversesum*10)+(sum%10);
sum=sum/10;
}
System.out.println(reversesum);
if(reversesum==r)
{System.out.println(i);
break;}
i++;
}
}
}
whats wrong with this code.The program is about " given a number X.find minimium positive integer Y required to make binary representation of
(X+Y) palindrome.for eg:X=6 Y=1".It works fine with values upto 12345 but it is not working with values 123456 and above.
To tell the truth, it is hard to read your code and find problem. I think it is too complicated with such simple problem. I offer you another solution.
E.g. you entered x=6, this is 110 in binary format. Your goal is to find another minimal value y that x+y=<binary palindrome>. For 110, maximum palindrome id 111 which is 7. So, all you need is just find a minimal 0 <= y <= (7-6) where x+y=<binary palindrome>.
Here is the code example. It is pretty easy and simple.
public static long toBinaryPalindrome(long num) {
for (long i = 0, total = allBits(Long.toBinaryString(num).length()) - num; i <= total; i++)
if (isBinaryPalindrome(num + i))
return i;
return -1;
}
private static boolean isBinaryPalindrome(long num) {
String str = Long.toBinaryString(num);
return str.equals(new StringBuilder(str).reverse().toString());
}
private static long allBits(int len) {
long res = 0;
for (int i = 0; i < len; i++)
res |= 1 << i;
return res;
}
I want to round my number if it exceeds 8 character long.
For example,
// Big number rounding using scientific notation
double myDouble1 = 123456789;// desired output: 1.23e+08
Another situation
// Rounding
double myDouble2 = 12345.5678901234; // Desired output: 12345.57
I've tried using String.format() with %.2g and %.7, but I couldn't achieve the desired output.
Here's the code that I've tried to come up with.
public String parseResult(String val){
String formatted = val;
try{
if(formatted.length() > 8){
double temp = Double.parseDouble(val);
if(temp % 1 == 0){
formatted = String.format("%.2g", temp);
}else{
formatted = String.format("%.7g", temp);
}
}
}
catch(NumberFormatException e)
{
}
return formatted;
}
public class SolutionMain
{
public static void main(String[] args)
{
double myDouble1 = 123456789; // Desired output: 1.23e+08
double myDouble2 = 12345.5678901234; // Desired output: 12345.57
System.out.println(parseResult(myDouble1));
System.out.println(parseResult(myDouble2));
}
public static String parseResult(Double myDouble)
{
DecimalFormat format = null;
if(myDouble.toString().length() > 8)
{
if(myDouble % 1 == 0)
format = new DecimalFormat("0.00E00");
else
format = new DecimalFormat("#.00");
}
return format.format(myDouble);
}
}
For more pattern format details: Customizing Formats
class ScientificNot
{
public static String getScientifiNotation(double n)
{
int n1=(int)n;
String s0=String.valueOf(n-(double)n1);
String s1=String.valueOf((double)((int)n));
int in=s1.indexOf(".");
String mantissa=null,exp=null;
if(n>=10000000.0)
{
if(s1.length()>8)
{
mantissa=s1.substring(0,3);
exp=s1.substring(3);
double man=Double.parseDouble(mantissa)/100.0;
return(man+"e"+exp.length());
}
else
return s1;
}
else if(s0.length()>8)
{
double num=(((double)((int)(n*1000))));
int dp=((int)num%1000);
if(dp%10>=5)
dp=(dp-(dp%10))+10;
return String.valueOf(((int)num/1000)+"."+(dp/10));
}
else{
s1=""+n;
}
return s1;
}
}
I'm relatively new to java and learning OOP and I have a project to make a number converter that can convert a value of any base to decimal, or a decimal value to any base.
I've tested decimal to a different base and that's working fine for me, but the decimal to base [2, 8, whatever] isn't working. Any help?
public class NumberConverter
{
private int decimal; // always stores the decimal equivalent, regardless of base
private int base;
private String strValue;
/** default set to base 10 w/ a value of 0 */
public NumberConverter()
{
decimal = 0;
base = 10;
strValue="0";
}
/** base 10 value is used to set decimal, base and strValue
* note: toBaseX can do this for you also */
public NumberConverter(int value)
{
decimal = value;
base = 10;
strValue = "" + value;
}
/** sets the strValue and base based on parameters
* strValue is only stored in uppercase
* decimal is set here as well provided newValue is valid */
public NumberConverter(int newValue, int newBase)
{
decimal = 0;
strValue = newValue + "";
base = newBase;
}
//**** Accessor Methods ****//
public String getValue()
{
return strValue;
}
public int getBase()
{
return base;
}
public int getDecimal()
{
return decimal;
}
/** sets the strValue and base based on parameters
* decimal is set here as well, with a call to baseXToDec() */
public void setValue(String newValue, int newBase)
{
strValue = newValue;
base = newBase;
if (isValid())
decimal = baseXToDec();
else
decimal = 0;
}
public boolean isValid()
{
boolean valid = true;
for (int i=0; i<strValue.length()-1; i++)
{
if ((strValue.charAt(i)>47 && strValue.charAt(i)<58) || (strValue.charAt(i)>64 && strValue.charAt(i)<71))
valid = true;
else
valid = false;
}
return valid;
}
/** base of this object is set to x and strValue is the String value in base x
* strValue is also returned, just for good measure
* #param x the number base to convert to */
public String toBaseX(int x)
{
String strResult = "", strRev;
base = x;
int div = decimal, mod;
if (decimal == 0)
return "0";
while(div != 0)
{
mod = div % x;
if (mod > 10)
strResult += (char)(mod+55);
else
strResult += (char)(mod+48);
div = div / x;
}
strRev = reverseString(strResult);
strValue = strRev;
return strRev;
}
/** take the currently stored strValue and calculate and return the decimal value */
public int baseXToDec()
{
int exponent = strValue.length()-1;
for (int i=0; i<strValue.length(); i++)
{
// update result
decimal += (strValue.charAt(i) * Math.pow(base, exponent));
// decrement exponent
exponent--;
}
base = 10;
strValue = "" + decimal;
return decimal;
}
/** this is a helper method only
* the integer value of digit is returned
* -1 is the return value for an error
* #param ch a valid digit for the given number base */
private int charToValue(char ch)
{
}
/** This is a helper method that returns strRev as a reversed version
* #param strFwd the string to be reversed */
private String reverseString(String strResult)
{
String strRev = "";
for ( int i = strResult.length() - 1 ; i >= 0 ; i-- )
strRev= strRev + strResult.charAt(i);
return strRev;
}
/** a String with the current base and value is returned */
public String toString()
{
String result = "In base " + getBase() + " the value is "+ getValue() + ".\n";
return result;
}
}
strValue.charAt(i) this is the problem: it returns a character code for the digit, not the integer value it represents. For example, the code for character '0' is 48 etc. You need to convert it into the actual integer value before you can use it like that.
One (non-portable, and frowned upon) way is to subtract 48 (or '0'), as suggested in the comment. This relies on the fact that the digits in ASCII are coded sequentially, so 49 would be '1', 50 - '2' etc. It'll do what you want.
A (slightly) better way is Character.getNumericValue(strValue.charAt(i)).
It'll do the same thing behind the curtain, but will also work in exotic languages (like Indian, Easter Arabic etc.), that use different symbols for digits. Not that your little program will ever need that, just a good practice to adopt for the future.
Edit: same applies to isValid() function as well. Character.isDigit() is a better option thаn explicitly looking at character codes. You could also potentially simplify it by replacing the whole thing with strValue.matches("\\d+"); (\\d is a regex code for "digit", so this returns true when your string contains only digits.
I believe you are trying re-invent the wheel here. Java already has pretty easy implementation.
Integer.toString(number, base) method will help you to convert to another base.
Example:
System.out.println(Integer.toString(10, 5));
Look Integer.parseInt() method also where ever needed.
I haven't gotten around to isValid yet; subtracting the value of 0 as suggested and using a separate local variable did give me the correct output.
public int baseXToDec()
{
int decVal = 0, exponent = strValue.length()-1;
for (int i=0; i<strValue.length(); i++)
{
// update result
decVal += ((strValue.charAt(i)-'0') * Math.pow(base, exponent));
// decrement exponent
exponent--;
}
base = 10;
strValue = "" + decVal;
decimal = decVal;
return decimal;
}
Your method isValid contains true if the last char is valid and false if the last char is not valid.
Change it:
public boolean isValid()
{
for (int i=0; i<strValue.length()-1; i++)
{
if (!((strValue.charAt(i)>47 && strValue.charAt(i)<58) || (strValue.charAt(i)>64 && strValue.charAt(i)<71)))
return false;
}
return true;
}
Do you know of any method to make sure users can only enter figures with a maximum number of decimals.
I'm not sure how to address this problem. In the MS SQL database I'm going to send data from my app I've got columns with this type decimal(8,3)
Now considering the data type of the column that's finally going to store the value I want to validate in Android, I've considered these two cases:
If the user enters a number with no decimals, the maximum number of digits must be 8
If the user enters a number with decimals, the maximum number of digits must be 8 (including the digits to the right of the decimal point)
Now I'm sure about the first case, but not so much about the second. Is it right to keep the number of maximum digits fixed(for example, always 8)? Or should I consider allowing a maximum of 8 digits to the left and 3 to the right of the decimal point?
Either way this is what I've been trying in Android:
mQuantityEditText.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
String str = mQuantityEditText.getText().toString();
DecimalFormat format = (DecimalFormat) DecimalFormat
.getInstance();
DecimalFormatSymbols symbols = format.getDecimalFormatSymbols();
char sep = symbols.getDecimalSeparator();
int indexOFdec = str.indexOf(sep);
if (indexOFdec >= 0) {
if (str.substring(indexOFdec, str.length() - 1).length() > 3) {
s.replace(0, s.length(),
str.substring(0, str.length() - 1));
}
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
});
Even though, the above code handles the maximum number of decimal places. It does not limit the total number of digits allowed in the EditText.
Do you think you could help me improve my code so that it handles both the maximum number of decimal places and the total number of digits allowed in a EditText (considering both numbers to the left and to the right of the decimal point)
EDIT
Well, now I'm trying what João Sousa suggested and here's what I've tried:
1) I defined a class that implements InputFilter
public class NumberInputFilter implements InputFilter {
private Pattern mPattern;
public NumberInputFilter(int precision, int scale) {
String pattern="^\\-?(\\d{0," + (precision-scale) + "}|\\d{0," + (precision-scale) + "}\\.\\d{0," + scale + "})$";
this.mPattern=Pattern.compile(pattern);
}
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) {
if (end > start) {
// adding: filter
// build the resulting text
String destinationString = destination.toString();
String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd);
// return null to accept the input or empty to reject it
return resultingTxt.matches(this.mPattern.toString()) ? null : "";
}
// removing: always accept
return null;
}
}
2) Tried to use the class like this :
mQuantityEditText.setFilters(new InputFilter[] { new NumberInputFilter(8,3)} );
I would go for a filter in the edit text itself with the power of regex. First the regex expression:
^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$
Maybe there are multiple ways to improve this expression, but this does trick.
And now just set an input filter in the edittext, like this:
final String regex = "^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$";
((EditText)rootView.findViewById(R.id.editText1)).setFilters(new InputFilter[] {
new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) {
if (end > start) {
// adding: filter
// build the resulting text
String destinationString = destination.toString();
String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd);
// return null to accept the input or empty to reject it
return resultingTxt.matches(regex) ? null : "";
}
// removing: always accept
return null;
}
}
});
Btw, I just tested this code and what it does is:
The user can enter a maximum of 8 digits;
As soon as the user enters a '.', the maximum decimal digits allowed are 8.
Did I correctly understand the problem you described?
-- EDIT
Ok, I was almost there. From what I understand, decimal(8,3) means at most 8 digits including digits to the left or right of the decimal point, ranging from -99999.999 to 99999.999.
At least that's what I understand from this sentence Standard SQL requires that DECIMAL(5,2) be able to store any value with five digits and two decimals, so values that can be stored in the salary column range from -999.99 to 999.99. Even though it's from the MySQL documentation the MSSQL docs seem to do the same.
I have answser for you, me also suffered lot in this kind of situation.:D :P
I have implemented this for maximum of 4 digits to the left and 2 to the right of the decimal point ex: 4444.99
so small changes need to implement what i did:
Need to do following changes
1) copy CustomTextWatcher.java to track input of editText.
import java.text.NumberFormat;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;
public class CustomTextWatcher implements TextWatcher {
private NumberFormat nf = NumberFormat.getNumberInstance();
private EditText et;
private String tmp = "";
private int moveCaretTo;
private static final int INTEGER_CONSTRAINT = 4;
private static final int FRACTION_CONSTRAINT = 2;
private static final int MAX_LENGTH = INTEGER_CONSTRAINT
+ FRACTION_CONSTRAINT + 1;
public CustomTextWatcher(EditText et) {
this.et = et;
nf.setMaximumIntegerDigits(INTEGER_CONSTRAINT);
nf.setMaximumFractionDigits(FRACTION_CONSTRAINT);
nf.setGroupingUsed(false);
}
public int countOccurrences(String str, char c) {
int count = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == c) {
count++;
}
}
return count;
}
#Override
public void afterTextChanged(Editable s) {
et.removeTextChangedListener(this); // remove to prevent stackoverflow
String ss = s.toString();
int len = ss.length();
int dots = countOccurrences(ss, '.');
boolean shouldParse = dots <= 1
&& (dots == 0 ? len != (INTEGER_CONSTRAINT + 1)
: len < (MAX_LENGTH + 1));
if (shouldParse) {
if (len > 1 && ss.lastIndexOf(".") != len - 1) {
try {
if (ss.contains(".")) {
String[] integerFractionStrings = ss.split("\\.");
Log.v("Check SS ", ss);
Log.v("second string", "Found"
+ integerFractionStrings.length);
if (integerFractionStrings.length > 1) {
Log.v("integerFractionStrings",
integerFractionStrings[1]);
if (integerFractionStrings[1].length() == 1
&& integerFractionStrings[1].charAt(0) == '0') {
et.setText(ss);
Log.v("second string", "size 1");
} else {
Log.v("second string", "> 1");
Double d = Double.parseDouble(ss);
if (d != null) {
et.setText(nf.format(d));
}
}
}
} else {
Log.v("First string", "No dot");
Double d = Double.parseDouble(ss);
if (d != null) {
et.setText(nf.format(d));
}
}
} catch (NumberFormatException e) {
}
}
} else {
Log.v("second string", "size 1");
et.setText(tmp);
}
et.addTextChangedListener(this); // reset listener
// tried to fix caret positioning after key type:
if (et.getText().toString().length() > 0) {
if (dots == 0 && len >= INTEGER_CONSTRAINT
&& moveCaretTo > INTEGER_CONSTRAINT) {
moveCaretTo = INTEGER_CONSTRAINT;
} else if (dots > 0 && len >= (MAX_LENGTH)
&& moveCaretTo > (MAX_LENGTH)) {
moveCaretTo = MAX_LENGTH;
}
try {
et.setSelection(et.getText().toString().length());
// et.setSelection(moveCaretTo); <- almost had it :))
} catch (Exception e) {
}
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
moveCaretTo = et.getSelectionEnd();
tmp = s.toString();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int length = et.getText().toString().length();
if (length > 0) {
moveCaretTo = start + count - before;
}
}
}
2) set this class to check your editText by following.
EditText review_food_Price;
review_food_Price = (EditText) findViewById(R.id.food_Price);
review_food_Price.setRawInputType(InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_FLAG_DECIMAL);
review_food_Price.addTextChangedListener(new CustomTextWatcher(
review_food_Price));
Hope you can convert my code according to your need.
The problem that you describe is precisely what a Masked EditText is meant to be used for. :)