I have both the phone number and address (including the zipcode) in the same TextView. I want the phone number to be clickable to call; however, this is making the zip code also clickable to make a phone call. How do I make it no longer clickable without creating another TextView? Thanks!
tvInfo.setText(Html.fromHtml("John Smith<br>123 Fake Street<br>Faketown, FK 12345<br><b>(804) 932-3300</b><br>"));
Linkify.addLinks(tvInfo, Linkify.PHONE_NUMBERS);
android will regard digits with count >=5 as phone numbers. so I think there will be at least 2 solutions:
1)a simple work around : if you are sure the length of phone numbers is more than 5, for example, at least 6 digits, you could make some work around:
private final static int MY_PHONE_NUMBER_MINIMUM_DIGITS = 6;
Linkify.addLinks(main, Patterns.PHONE, "tel:", new Linkify.MatchFilter() {
public final boolean acceptMatch(CharSequence s, int start, int end) {
int digitCount = 0;
for (int i = start; i < end; i++) {
if (Character.isDigit(s.charAt(i))) {
digitCount++;
if (digitCount >= MY_PHONE_NUMBER_MINIMUM_DIGITS ) {
return true;
}
}
}
return false;
}
}, Linkify.sPhoneNumberTransformFilter);
this workaround is based on android source code of Linkify, in Linkify, the method:
gatherLinks(links, text, Patterns.PHONE,
new String[] { "tel:" },
sPhoneNumberMatchFilter, sPhoneNumberTransformFilter);
will be called, while sPhoneNumberMatchFilter will filter the digits less than 5:
public static final MatchFilter sPhoneNumberMatchFilter = new MatchFilter() {
public final boolean acceptMatch(CharSequence s, int start, int end) {
int digitCount = 0;
for (int i = start; i < end; i++) {
if (Character.isDigit(s.charAt(i))) {
digitCount++;
if (digitCount >= PHONE_NUMBER_MINIMUM_DIGITS/*=5*/) {
return true;
}
}
}
return false;
}
};
so we just replace the "PHONE_NUMBER_MINIMUM_DIGITS" with 6
2)a more complicated solution is, if your phone numbers are in a more specific format for example, must be something like "(xxx)xxx-xxxx", you could use your own pattern to replace the Patterns.PHONE, to extract and apply links of phone numbers more accurately
Related
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 need to print out everything between a start codon atg and one of three end codons tga, taa, and tag. I have been trying to solve this problem for a couple days now but I can't seem to find a way to remove the start codon from what gets printed out at the end EX: If you use my code it will print out ATGAAA but I need it to print out only AAA.
public class GeneFinderYang {
public static int findStopIndex(String dna, int index){
int stop1 = dna.indexOf("tga", index);
if (stop1 == -1 || (stop1 - index) % 3 != 0) {
stop1 = dna.length();
}
int stop2 = dna.indexOf("taa", index);
if (stop2 == -1 || (stop2 - index) % 3 != 0) {
stop2 = dna.length();
}
int stop3 = dna.indexOf("tag", index);
if (stop3 == -1 || (stop3 - index) % 3 != 0) {
stop3 = dna.length();
}
return Math.min(stop1, Math.min(stop2,stop3));
}
public static void printAll(String dna){
String dnaLow = dna.toLowerCase();
int start = 0;
while (true) {
int loc = dnaLow.indexOf( "atg", start );
int stop = findStopIndex( dnaLow, loc+3 );
if ( stop != dna.length() ) {
System.out.println( dna.substring(loc, stop) );
start = stop + 3;
} else {
start = start + 3;
}
}
}
// demo
public static void testFinder() {
String dna1 = "ATGAAATGAAAA";
System.out.println("DNA string is: \n" +dna1);
System.out.println("Genes found are:");
printAll(dna1);
System.out.print("\n");
}
public static void main(String[] args) {
testFinder();
}
}
The error is in your printAll() function.
public static void printAll(String dna){
String dnaLow = dna.toLowerCase();
int start = 0;
while (true) {
int loc = dnaLow.indexOf( "atg", start );
int stop = findStopIndex( dnaLow, loc+3 );
if ( stop != dna.length() ) {
System.out.println( dna.substring(loc, stop) );
start = stop + 3;
} else {
start = start + 3;
}
}
}
The main issue here is you are using too many variables. You should only need the start variable, not the loc variable. If we switch all occurrences of loc and get rid of the ugly arithmetic the function will look like this:
public static void printAll(String dna){
String dnaLow = dna.toLowerCase();
int start = 0;
while (true) {
start = dnaLow.indexOf( "atg", start ) + 3;
int stop = findStopIndex( dnaLow, start );
if ( stop != dna.length() ) {
System.out.println( dna.substring(start, stop) );
start = stop + 3;
} else {
start = start + 3;
}
}
}
But we are not done. If we run the code this way, things will work much the same as your code currently does. Now what the indexOf() function does is return the index of the start of the string. So when you are finding the index of ATG, it returns zero. Well, the string you want starts at index 3 because atg is three characters long. This is easily solved by adding three to the result. You need to do this everytime, not just when your if statement fails. If this is supposed to output multiple genes, you might try restructuring your code a bit, preferably away from an infinite loop. The main issue being that in your if statement, you are checking if we are at the end of the string and then setting start equal to stop+3. But then the loop runs again and it gets set to the index of atg again. This is a symptom of ditching the loc variable admittedly.
public static void printAll(String dna) {
String dnaLow = dna.toLowerCase();
int start = 0;
int stop = 0;
start = dnaLow.indexOf( "atg", start ) + 3;
while (start < dna.length())
{
stop = findStopIndex( dnaLow, start );
System.out.println( dna.substring(start, stop) );
start = stop + 3;
}
}
I also initialized the stop variable outside of the loop, but that is personal preference and it doesn't matter.
Edit:
For loops are your friend when dealing with multiple items. This is obvious in the findStopIndex() function. This function is actually easier to write with a for loop. What we will do is create arrays to hold our codons and indexes so there is one index per codon. Then we iterate through them trying find a stop index for each. If we don't find one, then we set the corresponding index to the end of the string.
public static int findStopIndex(String dna, int index){
String endCodons[] = { "tga", "taa", "tag"};
int stopIndexes[] = new int[3];
for(int i = 0; i<3 ;i++)
{
stopIndexes[i] = dna.indexOf(endCodons[i], index);
if(stopIndexes[i]==-1||(stopIndexes[i] - index) % 3 != 0)
stopIndexes[i] = dna.length();
}
return Math.min(stopIndexes[0], Math.min(stopIndexes[1],stopIndexes[2]));
}
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. :)
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
For a school project i have a list of 50k containers that arrive on a boat.
These containers need to be sorted in a list in such a way that the earliest departure DateTimes are at the top and the containers above those above them.
This list then gets used for a crane that picks them up in order.
I started out with 2 Collection.sort() methods:
1st one to get them in the right X>Y>Z order
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
return positionSort(contData1.getLocation(),contData2.getLocation());
}
});
Then another one to reorder the dates while keeping the position in mind:
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
int c = contData1.getLeaveDateTimeFrom().compareTo(contData2.getLeaveDateTimeFrom());
int p = positionSort2(contData1.getLocation(), contData2.getLocation());
if(p != 0)
c = p;
return c;
}
});
But i never got this method to work..
What i got working now is rather quick and dirty and takes a long time to process (50seconds for all 50k):
First a sort on DateTime:
Collections.sort(containers, new Comparator<ContainerData>()
{
#Override
public int compare(ContainerData contData1, ContainerData contData2)
{
return contData1.getLeaveDateTimeFrom().compareTo(contData2.getLeaveDateTimeFrom());
}
});
Then a correction function that bumps top containers up:
containers = stackCorrection(containers);
private static List<ContainerData> stackCorrection(List<ContainerData> sortedContainerList)
{
for(int i = 0; i < sortedContainerList.size(); i++)
{
ContainerData current = sortedContainerList.get(i);
// 5 = Max Stack (0 index)
if(current.getLocation().getZ() < 5)
{ //Loop through possible containers above current
for(int j = 5; j > current.getLocation().getZ(); --j)
{ //Search for container above
for(int k = i + 1; k < sortedContainerList.size(); ++k)
if(sortedContainerList.get(k).getLocation().getX() == current.getLocation().getX())
{
if(sortedContainerList.get(k).getLocation().getY() == current.getLocation().getY())
{
if(sortedContainerList.get(k).getLocation().getZ() == j)
{ //Found -> move container above current
sortedContainerList.add(i, sortedContainerList.remove(k));
k = sortedContainerList.size();
i++;
}
}
}
}
}
}
return sortedContainerList;
}
I would like to implement this in a better/faster way. So any hints are appreciated. :)
I think you probably want to sort with a single Comparator that compares on all of the criteria. E.g.:
compareTo(other)
positionComparison = this.position.compareTo(other.position)
if positionComparison != 0
return positionComparison
return this.departureTime.compareTo(other.departureTime)