Can someone please help me with some code I have it is supposed to check that the string being passed is of 2 string and 3 ints which works fine, but if the 1 int is a zero it doesn't work
so if it was CM044 it won't work, CM450 will work can someone please help.
public boolean checkModule(String Module) {
if(Module.length() == 5){
boolean hasString = false;
boolean hasInt = false;
String letters = Module.substring(0, 2);
Pattern p = Pattern.compile("^[a-zA-Z]+$");
Matcher m = p.matcher(letters);
if (m.matches()) {
hasString = true;
}
String numbers=Module.substring(2,5);
try {
int num = Integer.parseInt(numbers);
String n = num + "";
if (num >0 && n.length() == 3)
hasInt = true;
} catch (Exception e) {
}
if (hasInt && hasString) {
return true;
}
}else{
return false;
}
return false;
}
Thanks
If you are going to use regular expressions you should definitely stick with them and not vary in and out.
package com.examples;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
new Main();
}
public Main() {
String[] testInputs = new String[] {"CM045", "CM450"};
for(String input : testInputs) {
System.out.println("The module " + input + " is " + (checkModule(input) ? "valid" : "invalid"));
}
}
public boolean checkModule(String Module){
Pattern p = Pattern.compile("[A-Z]{2}[0-9]{3}");
Matcher m = p.matcher(Module.toUpperCase());
return m.matches();
}
}
if the String is "045" the Integer value is 45 and so the length of num can't be 3
Use this
if(num>=0) {
hasInt = true;
}
and it has to work
Related
I have developed an app, sort of an text reader, and need to introduce a new functionality to it (users are asking for it- I've intended to incorporate it all along, just that I never figured out how to do it). I'm generating an html from the text and displaying it in a webview. I want the user to be able to select a section of the text and then open the context menu. What I want to identify is on which section he has longClicked on (each line of the html consists of pre-formatted line/section number, the line text and may be finished with a href link), and which part of it was selected. Once I figure the first part out, the second is just a matter of sorting it out.
I've tried using <span id='someuniquenumber'> for the line text, but webView does not recognize it as an anchor*. I've also, unsuccessfully, tried to enable text selection on links (which IMHO is not a desirable option, but will resort to it, if there are no other options left).
Here's an example of the text selection problem- I want to be able to identify the selection as "line 5, words 4 through 10", or at least that the user has selected the text from the line marked as 5.
Any help would be greatly appreciated- just bear in mind that I can affect both the webView behaviour and the HTML code displayed. Thanks in advance. :)
event handler returns get extra=0 in type='null'
If I use tags, I do not know the way to allow text selection within that link, whereas without it I cannot identify the element user has clicked on (and the selected text may certainly not be unique, and therefore may not be searched within HTML).
EDIT
Here's the code I have regarding webView (onCreate in MainActivity):
mWebView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
int temp = url.lastIndexOf("/") + 1;
String link = url.substring(temp);
if (link.charAt(0) == 'L') {
link = link.substring(1);
LinksFragment mLinksFragment = LinksFragment.newInstance(Integer.valueOf(link),textZoom,zoomAll,sans,fragNo);
mLinksFragment.show(fm,"fragment_links");
} else if (link.charAt(0) == 'C') {
// show or add comment
} else {
// follow link
// append link to clipboard
ClipData tmp = myCB.getPrimaryClip();
if (!myCB.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
tmp = ClipData.newPlainText("text","");
myCB.setPrimaryClip(tmp);
}
ClipData.Item tmpI = tmp.getItemAt(0);
String ts = tmpI.getText().toString();
ts += link + " ";
tmp = ClipData.newPlainText("text",ts);
myCB.setPrimaryClip(tmp);
}
return true;
}
});
// detect clicked element
mWebView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
WebView.HitTestResult hr = ((WebView)view).getHitTestResult();
Toast.makeText(MainActivity.this, "getExtra = "+ hr.getExtra() + "Type= " + hr.getType(),
Toast.LENGTH_LONG).show();
//return true;
return false;
}
});
mWebView.getSettings().setDefaultFontSize(14);
mWebView.setBackgroundColor(0x00000000);
mWebView.getSettings().setBuiltInZoomControls(true);
mWebView.getSettings().setDisplayZoomControls(false);
updateFields(); // applies custom fontface and fontsize to elements incl. mWebView
mWebView.loadDataWithBaseURL("file:///android_asset/",wV,"text/html; charset=utf-8","utf-8",null);
And here's the code for generating html inserted into the webView (a separate function fetching text, adding headings and chapter titles, formatting the text)-the actual text is stored in tmpStr variable:
public String fetchText(Bible mB, boolean append, boolean filter, String wV) {
BibleInfo.Error mE;
String tN;
char tT;
int[] Lines;
String[] Lttrs;
int[] noVerses = new int[3];
String fS1 = "<p class='ps'>";
String Psalm = getResources().getString(R.string.Psalm);
String Chapter = getResources().getString(R.string.Chapter);
boolean estExc = false;
char lttr = 'a'-1;
mE = mB.mBI.mE;
int tmp = 0;
for (int i=0; i<3; i++) {
tmp += mB.mBI.noBooks(i);
noVerses[i] = mB.mBI.getLine(tmp,1,1);
}
// separating link data
int cnt = 0;
Lines = new int[mB.mLink.getLines().length];
Lttrs = new String[mB.mLink.getLines().length];
for (String tS:mB.mLink.getLines()) {
tN = "";
Lttrs[cnt] = "";
for (tmp=0; tmp<tS.length(); tmp++) {
tT = tS.charAt(tmp);
if (tT>='0' && tT<='9') {
tN += tT;
} else {
Lttrs[cnt] += tT;
}
}
Lines[cnt++] = Integer.valueOf(tN);
}
if (!append) {
wV = "";
}
noVerses = mB.mBI.getTriLink(Lines[0],mE);
if ((noVerses[1] == 0 || (noVerses[1] == 1 && noVerses[0] != mB.mBI.getSirach())) && mB.mLink.isLong()) {
if (mB.mBI.getTitles() != null) {
wV += "<h1>" + mB.mBI.getTitles()[noVerses[0]] + "</h1>";
}
}
for (int i=0; i<Lines.length; i++) {
int tX = Lines[i];
int[] temp = mB.mBI.getTriLink(tX, mE);
if (temp[2] == 1 && mB.mLink.isLong() && temp[1] != 0) {
if (temp[0] == mB.mBI.getPsalms()) {
wV += "<h2>" + Psalm + " " + temp[1] + "</h2>";
} else {
wV += "<h2>" + Chapter + " " + temp[1] + "</h2>";
}
}
String tmpStr = mB.getLineText(tX - 1,filter);
if (noVerses[0] == mB.mBI.getPsalms()) {
wV += fS1;
if (Lttrs[i] != "") {
tmpStr = parseVerse(tmpStr,Lttrs[i]);
}
tmpStr = tmpStr.replace(mB.mBI.mSeparator, "<br>");
} else {
wV += "<p>";
if (noVerses[0] == mB.mBI.getEsther()) {
int noBrks = 0;
int lastOccurrence = 0;
if ((temp[1]==1) & (temp[2]==1)) {
estExc = true;
while (lastOccurrence != -1){
lastOccurrence = tmpStr.indexOf(mB.mBI.mSeparator,lastOccurrence);
String tStr = "<br><sup>" + temp[2] + (char)(98+noBrks) + "</sup> ";
if (lastOccurrence != -1) {
if (noBrks == 0) {
tmpStr = "<span id='apoch'>" + tmpStr;
}
tmpStr = tmpStr.replaceFirst("\\|", tStr);
noBrks +=1;
}
}
if (tmpStr.lastIndexOf(mB.mBI.mSeparator) != -1) {
tmpStr += "</span>";
}
// remove character before last </sup>
} else {
estExc = false;
while (lastOccurrence != -1){
lastOccurrence = tmpStr.indexOf(mB.mBI.mSeparator,lastOccurrence);
String tStr = "<br><sup>" + temp[2] + (char)(97+noBrks) + "</sup> ";
if (lastOccurrence != -1) {
if (noBrks == 0) {
tmpStr = "<span id='apoch'>" + tmpStr;
}
tmpStr = tmpStr.replaceFirst("\\|", tStr);
noBrks +=1;
}
}
if (noBrks != 0) {
tmpStr += "</span>";
}
tmpStr = tmpStr.replaceFirst("<span id='apoch'>","");
tmpStr = tmpStr.replaceFirst("<br>","<br><span id='apoch'>");
}
}
}
// add hyperlink for links
if (!TextUtils.isEmpty(mB.getLinks()[tX-1])) {
lttr++;
if (lttr>'z') { lttr = 'a'; }
String ts= "<sup><span id='links'><a href='L" + (tX-1) + "'>" + lttr;
ts += "</a></span></sup>";
tmpStr += ts;
}
if (estExc) {
wV += "<sup>" + temp[2] + "a</sup> " + tmpStr + "</p>";
} else {
wV += "<sup>" + temp[2] + "</sup> " + tmpStr + "</p>";
}
}
wV = fS2 + wV;
return wV;
}
Calls to log events or set user properties fired from within a WebView must be forwarded to native code before they can be sent to Google Analytics for Firebase.
Implement JavaScript handler
The first step in using Google Analytics for Firebase in a WebView is to create JavaScript functions to forward events and user properties to native code. The following example shows how to do this in a way that is compatible with both Android and iOS native code
function logEvent(name, params) {
if (!name) {
return;
}
if (window.AnalyticsWebInterface) {
// Call Android interface
window.AnalyticsWebInterface.logEvent(name, JSON.stringify(params));
} else if (window.webkit
&& window.webkit.messageHandlers
&& window.webkit.messageHandlers.firebase) {
// Call iOS interface
var message = {
command: 'logEvent',
name: name,
parameters: params
};
window.webkit.messageHandlers.firebase.postMessage(message);
} else {
// No Android or iOS interface found
console.log("No native APIs found.");
}
}
function setUserProperty(name, value) {
if (!name || !value) {
return;
}
if (window.AnalyticsWebInterface) {
// Call Android interface
window.AnalyticsWebInterface.setUserProperty(name, value);
} else if (window.webkit
&& window.webkit.messageHandlers
&& window.webkit.messageHandlers.firebase) {
// Call iOS interface
var message = {
command: 'setUserProperty',
name: name,
value: value
};
window.webkit.messageHandlers.firebase.postMessage(message);
} else {
// No Android or iOS interface found
console.log("No native APIs found.");
}
}
Implement native interface
public class AnalyticsWebInterface {
public static final String TAG = "AnalyticsWebInterface";
private FirebaseAnalytics mAnalytics;
public AnalyticsWebInterface(Context context) {
mAnalytics = FirebaseAnalytics.getInstance(context);
}
#JavascriptInterface
public void logEvent(String name, String jsonParams) {
LOGD("logEvent:" + name);
mAnalytics.logEvent(name, bundleFromJson(jsonParams));
}
#JavascriptInterface
public void setUserProperty(String name, String value) {
LOGD("setUserProperty:" + name);
mAnalytics.setUserProperty(name, value);
}
private void LOGD(String message) {
// Only log on debug builds, for privacy
if (BuildConfig.DEBUG) {
Log.d(TAG, message);
}
}
private Bundle bundleFromJson(String json) {
// ...
}
}
Once you have created the native interface, register it with your WebView so that it is visible to Javascript code running in the WebView:
// Only add the JavaScriptInterface on API version JELLY_BEAN_MR1 and above, due to
// security concerns, see link below for more information:
// https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object,%20java.lang.String)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
mWebView.addJavascriptInterface(
new AnalyticsWebInterface(this), AnalyticsWebInterface.TAG);
} else {
Log.w(TAG, "Not adding JavaScriptInterface, API Version: " + Build.VERSION.SDK_INT);
}
Source: Firebase
I don't know why but the toast doesn't appear when I run the program. This is my code:
class Number {
int number;
public boolean isSquare() {
double squareRoot = Math.sqrt(number);
if (squareRoot==Math.floor(squareRoot)) {
return true;
} else {
return false;
}
}
public boolean isTriangular() {
int x = 1;
int triangularNumber = 1;
while(triangularNumber<number) {
x++;
triangularNumber = triangularNumber + x;
}
if (triangularNumber == number) {
return true;
} else {
return false;
}
}
}
public void idButton (View view) {
EditText inputNumber = (EditText) findViewById(R.id.inputNumber);
Number myNumber = new Number();
myNumber.number = Integer.parseInt(inputNumber.getText().toString());
String message = "";
if (myNumber.isSquare()){
if (myNumber.isTriangular()){
message = myNumber.number + " your number is triangular and square";
}
}
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
After compiling there's no error in the code, please guide me what should be improved on the code since I'm still beginner. Could you help me? Thanks.
String message = "";
if (myNumber.isSquare()){
if (myNumber.isTriangular()){
message = myNumber.number + " your number is triangular and square";
}
}
In this code, you haven't write any else statement. What if the number is neither square nor triangular? In both of these scenerios you will get an empty message as you have declared message = "";
So write your code as
String message = "";
if (myNumber.isSquare()){
if (myNumber.isTriangular()){
message = message+myNumber.number + " your number is triangular and square";
}
else
{
message = message+"No triangular";
}
}
else
{
message = message+"No square";
}
Is there a way in which I can display the list of Time zones in a format like (GMT+1.00) Windhoek like the way we see in S Planner on the Android app?
Can anyone help me in sorting out this issue?
Thanks in adavance
First I suggest you to create a wrapper class to manage the format of TimeZone objects as follow:
public class TimeZoneWrapper {
private final TimeZone timeZone;
private String timeZoneID;
private String timeZoneDisplay;
private String timeZoneRawDisplayName;
public TimeZoneWrapper(final TimeZone timeZone) {
this.timeZone = timeZone;
setDisplayStrings();
}
private void setDisplayStrings() {
this.timeZoneID = timeZone.getID().replaceAll("_", " ");
int offset = timeZone.getRawOffset();
if (timeZone.inDaylightTime(new Date())) {
offset = offset + timeZone.getDSTSavings();
}
this.timeZoneRawDisplayName = timeZone.getDisplayName(false,
TimeZone.SHORT);
final int offsetHrs = offset / 1000 / 60 / 60;
final int offsetMins = offset / 1000 / 60 % 60;
if (offsetHrs + offsetMins == 0) {
this.timeZoneDisplay = "GMT";
} else {
String suffix = "";
if (offset < 0) {
suffix += "-";
} else {
suffix += "+";
}
if (offsetMins != 0) {
suffix += offsetHrs + "." + offsetMins;
} else {
suffix += offsetHrs;
}
this.timeZoneDisplay = "GMT" + suffix;
}
}
public String getTimeZoneID() {
return timeZoneID;
}
public String getTimeZoneDisplay() {
return timeZoneDisplay;
}
public String getTimeZoneRawDisplayName() {
return timeZoneRawDisplayName;
}
public TimeZone getTimeZone() {
return timeZone;
}
#Override
public final boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof TimeZoneWrapper)) {
return false;
}
final TimeZoneWrapper that = (TimeZoneWrapper) o;
return that.timeZone.equals(this.timeZone);
}
}
Once you have created (if you want) this wrapper class you can retrieve the TimeZones from your device with the following method in your mainActivity.
private List<TimeZoneWrapper> buildTimeZoneWrappers() {
final List<TimeZoneWrapper> timeZoneWrappers = new ArrayList<TimeZoneWrapper>();
final List<TimeZone> timeZones = new ArrayList<TimeZone>();
final String[] timeZoneIds = TimeZone.getAvailableIDs();
for (final String id : timeZoneIds) {
timeZones.add(TimeZone.getTimeZone(id));
}
for (final TimeZone timeZone : timeZones) {
timeZoneWrappers.add(new TimeZoneWrapper(timeZone));
}
return timeZoneWrappers;
}
Now you have a list of "well" formatted timezone, so if you need a picker with this value you simply have to create one with them.
String[] temp;
for (int i=0;i<timeZoneWrappers.size();i++){
temp[i]=timeZoneWrappers.get(i).getTimeZoneDisplay();
}
NumberPicker picker = new NumberPicker(getApplicationContext());
picker.setDisplayedValues(temp);
Let me know;)
I am trying to do a jigsaw puzzle app in android. In this, I have split a Bitmap into many small chunks. These chunks are then displayed in a GridViewNow I need to shuffle them. Then, I need to know each image chunk's actualPosition(where the piece was supposed to be, its actual location in the image) and its currentPosition(where the piece is currently located). actualPosition and currentPosition are 2 integer arrays. So is there a way that I can get each image chunk's currentPosition and actualPosition after the shuffling so that after every move that the user make I can check wether every image chunk's actualPosition equals its currentPosition. If so the user wins the game. Can anyone please help me out.
Below is the number puzzle game in pure Java that works. Can be run from command line.
It re-prints the whole matrix after every move (not pretty). It demos the basic game.
I hope most of the code is self explanatory. This shows the basic 2-dim mapping of the game, position tracking, validating based on numbers. Have fun.
package madhav.turangi.basic.game;
import java.util.Random;
import java.util.Scanner;
public class NumberPuzzle {
int size;
int[][] arr;
int spaceRow;
int spaceCol;
int turnsTook;
public NumberPuzzle(int size) {
this.size = size;
arr = new int[size][size];
}
void init()
{
for(int r=0; r<size; r++)
{
for(int c=0; c<arr[r].length; c++)
{
arr[r][c] = r*size + c + 1; // row-column of cell to its value equation
}
}
spaceRow = spaceCol = size - 1; // bottom-right cell index
}
int readUserInput()
{
int value = -1;
boolean valid = false;
do {
System.out.printf("To move space [0 - Up, 1 - Down, 2 - Left, 3 - Right] : ? ");
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
try
{
value = Integer.parseInt(line);
valid = (value>=0 && value<=3);
}
catch(NumberFormatException ne)
{
}
if(! valid) System.out.println("== Invalid ==");
} while (! valid);
return value;
}
void swap(int aRow, int aCol, int withRow, int withCol)
{
int temp = arr[aRow][aCol];
arr[aRow][aCol] = arr[withRow][withCol];
arr[withRow][withCol] = temp;
}
boolean moveUp()
{
if(spaceRow != 0)
{
int newSpaceRow = spaceRow - 1;
swap(spaceRow, spaceCol, newSpaceRow, spaceCol);
spaceRow--;
return true;
}
else
{
return false;
}
}
boolean moveDown()
{
if(spaceRow != size-1)
{
int newSpaceRow = spaceRow + 1;
swap(spaceRow, spaceCol, newSpaceRow, spaceCol);
spaceRow++;
return true;
}
else
{
return false;
}
}
boolean moveRight()
{
if(spaceCol != size-1)
{
int newSpaceCol = spaceCol + 1;
swap(spaceRow, spaceCol, spaceRow, newSpaceCol);
spaceCol++;
return true;
}
else
{
return false;
}
}
boolean moveLeft()
{
if(spaceCol != 0)
{
int newSpaceCol = spaceCol - 1;
swap(spaceRow, spaceCol, spaceRow, newSpaceCol);
spaceCol--;
return true;
}
else
{
return false;
}
}
void shuffle()
{
Random rnd = new Random(System.currentTimeMillis());
boolean moved = false;
int attemptCount = 1;
int maxMoves = 20;
for(int moveCount=0; moveCount<maxMoves; moveCount++, attemptCount++)
{
int randomMoveDir = rnd.nextInt(4);
moved = move(randomMoveDir);
if(! moved) moveCount--; //ensure maxMoves number of moves
}
System.out.printf("Shuffle attempts %d\n",attemptCount);
}
boolean move(int dir)
{
boolean moved = false;
switch(dir)
{
case 0 : // up
moved = moveUp();
break;
case 1 : // down
moved = moveDown();
break;
case 2 : // left
moved = moveLeft();
break;
case 3 : // right
moved = moveRight();
break;
}
return moved;
}
void prnArray()
{
System.out.println("-- -- -- -- --");
for(int[] row : arr)
{
for(int cellValue : row)
{
String v = (cellValue == 16 ? "" : String.valueOf(cellValue));
System.out.printf("%4s", v);
}
System.out.println();
}
System.out.println("-- -- -- -- --");
}
boolean validate()
{
for(int r=0; r<size; r++)
{
for(int c=0; c<arr[r].length; c++)
{
if(arr[r][c] != (r*size + c + 1))
{
return false;
}
}
}
return true;
}
boolean oneTurn()
{
int dir = readUserInput();
boolean moved = move(dir);
boolean won = false;
if(moved)
{
turnsTook++;
prnArray();
won = validate();
}
else
{
System.out.println("= Invalid =");
}
return won;
}
void play()
{
init();
System.out.println("Before shuffle");
prnArray();
shuffle();
prnArray();
boolean won = false;
while(! won)
{
won = oneTurn();
}
System.out.printf("Won in %d\n", turnsTook);
}
public static void main(String[] args)
{
NumberPuzzle puzzle = new NumberPuzzle(4);
puzzle.play();
}
}
I use the follow code to parse price from Google Play In-app Billing:
private static Number parsePrice(String priceFromGoogle) {
Locale currencyLocale = getCurrencyLocale(priceFromGoogle);
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(currencyLocale);
Number number = null;
try {
number = numberFormat.parse(priceFromGoogle);
} catch (ParseException e) {
e.printStackTrace();
}
return number;
}
private Locale getCurrencyLocale(String price) {
Locale locale = null;
for (Locale availableLocale : Locale.getAvailableLocales()) {
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(availableLocale);
try {
numberFormat.parse(price);
locale = availableLocale;
break;
} catch (ParseException e) {
//do nothing
}
}
return locale;
}
It works fine on my test devices and in my locale. But on some devices and in some countries I encounter prices like this: "Php1,337.07", "US$ 29.99", "MX$374.79". My approach doesn't work in this case.
Is there an universal approach to solve this problem?
Check their In-app billing sample project and modify SkuDetails.java so that you can get that information as well:
import org.json.JSONException;
import org.json.JSONObject;
/**
* Represents an in-app product's listing details.
*/
public class SkuDetails {
String mItemType;
String mSku;
String mType;
int mPriceAmountMicros;
String mPriceCurrencyCode;
String mPrice;
String mTitle;
String mDescription;
String mJson;
public SkuDetails(String jsonSkuDetails) throws JSONException {
this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails);
}
public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
mItemType = itemType;
mJson = jsonSkuDetails;
JSONObject o = new JSONObject(mJson);
mSku = o.optString("productId");
mType = o.optString("type");
mPrice = o.optString("price");
mPriceAmountMicros = o.optInt("price_amount_micros");
mPriceCurrencyCode = o.optString("price_currency_code");
mTitle = o.optString("title");
mDescription = o.optString("description");
}
public String getSku() { return mSku; }
public String getType() { return mType; }
public String getPrice() { return mPrice; }
public String getTitle() { return mTitle; }
public String getDescription() { return mDescription; }
public int getPriceAmountMicros() { return mPriceAmountMicros; }
public String getPriceCurrencyCode() { return mPriceCurrencyCode; }
#Override
public String toString() {
return "SkuDetails:" + mJson;
}
}
You can get the price in micros in the JSON retrieved by IabHelper.
This is not officially documented but here is how I've done it by editing SkuDetails.java :
public class SkuDetails {
...
Double mPriceMicros;
public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
...
String priceMicros = o.optString("price_amount_micros");
if (priceMicros != null) {
String format = new StringBuilder(priceMicros).insert(priceMicros.length() - 6, ".").toString();
mPriceMicros = Double.parseDouble(format);
}
}
...
public Double getPriceMicros() { return mPriceMicros; }
}
Hope this helps !
PS : I tried your Price class but it parsed 0.8 for 0,89 €
As Google Play may return prices in currency format which is unsupported by java.text.NumberFormat, I wrote my own implementation
public class Price {
private double value;
private String currency;
private String pattern;
private DecimalFormat decimalFormat;
private Price() {}
private static String currencyToDecimalFormat(String value, Price price) {
char decimalSeparator = '.';
char groupingSeparator = 0;
if (value.length() >= 3) {
char[] chars = value.toCharArray();
if (chars[chars.length - 2] == ',') {
decimalSeparator = ',';
chars[chars.length - 2] = '.';
} else if (chars[chars.length - 3] == ',') {
decimalSeparator = ',';
chars[chars.length - 3] = '.';
}
value = new String(chars);
}
if (value.contains(",")) {
groupingSeparator = ',';
value = value.replaceAll(",", "");
} else if (value.contains(" ")) {
groupingSeparator = ' ';
value = value.replaceAll(" ", "");
} else if (value.contains("\u00A0")) {
groupingSeparator = '\u00A0';
value = value.replaceAll("\u00A0", "");
}
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
if (groupingSeparator != 0) {
price.decimalFormat = new DecimalFormat("###,###.00");
symbols.setGroupingSeparator(groupingSeparator);
} else {
price.decimalFormat = new DecimalFormat("######.00");
}
symbols.setDecimalSeparator(decimalSeparator);
price.decimalFormat.setDecimalFormatSymbols(symbols);
return value.replaceAll(",", "");
}
public static Price parsePrice(String priceFromGoogle) {
Price price = new Price();
StringBuilder patternBuilder = new StringBuilder();
Pattern pattern = Pattern.compile("(?:[0-9]{1,3})(?:[0-9,.\\s\u00A0]+)");
Matcher matcher = pattern.matcher(priceFromGoogle);
matcher.find();
String priceString = matcher.group();
if (priceFromGoogle.indexOf(priceString) == 0) {
if (priceFromGoogle.length() != priceString.length()) {
price.currency = priceFromGoogle.substring(priceString.length());
} else {
price.currency = "";
}
} else {
price.currency = priceFromGoogle.substring(0, priceFromGoogle.indexOf(priceString));
}
price.currency = price.currency.trim();
if (priceFromGoogle.startsWith(price.currency)) {
patternBuilder.append("%1s");
char nextChar = priceFromGoogle.charAt(price.currency.length());
if (nextChar == ' ' || nextChar == 0xA0) {
patternBuilder.append(' ');
}
patternBuilder.append("%2$s");
} else {
patternBuilder.append("%2$s");
char prevChar = priceFromGoogle.charAt(priceFromGoogle.indexOf(price.currency) - 1);
if (prevChar == ' ' || prevChar == 0xA0) {
patternBuilder.append(' ');
}
patternBuilder.append("%1s");
}
price.pattern = patternBuilder.toString();
priceString = trim(priceString);
priceString = currencyToDecimalFormat(priceString, price);
price.value = Double.parseDouble(priceString);
return price;
}
#Override
public String toString() {
if (pattern != null) {
return String.format(pattern, currency, decimalFormat.format(value));
} else {
return "";
}
}
}
EDIT1:
Because of Google uses non-breaking space instead of usual space you need check this and use custom trim function:
public static String trim(String text) {
int start = 0, last = text.length() - 1;
int end = last;
while ((start <= end) && (text.charAt(start) <= ' ' || text.charAt(start) == 0xA0)) {
start++;
}
while ((end >= start) && (text.charAt(end) <= ' ' || text.charAt(end) == 0xA0)) {
end--;
}
if (start == 0 && end == last) {
return text;
}
return text.substring(start, end);
}