I am having problems with this NumberFormatException Invalid Long. The log cat is showing that the error is coming from the Long.parseLong part of the method.
public static String getDateTimeStr(String p_time_in_millis) {
SimpleDateFormat sdf = new SimpleDateFormat(DATE_TIME_FORMAT);
Date l_time = new Date(Long.parseLong(p_time_in_millis));
return sdf.format(l_time);
}
Can someone tell me why this code works fine when I fetch and display the data in certain calendars then in other calendars on my device I get this NumberFormatException Invalid Long please?
Edit: Here is the rest of the codeā¦
private void getEvents() {
Uri l_eventUri;
ArrayList<Map<String, String>> allStudents = new ArrayList<Map<String, String>>();
if (Build.VERSION.SDK_INT >= 8) {
l_eventUri = Uri.parse("content://com.android.calendar/events");
} else {
l_eventUri = Uri.parse("content://calendar/events");
}
String[] l_projection = new String[]{"title", "dtstart", "dtend"};
#SuppressWarnings("deprecation")
Cursor l_managedCursor = this.managedQuery(l_eventUri, l_projection, "calendar_id=" + m_selectedCalendarId, null, "dtstart DESC, dtend DESC");
if (l_managedCursor.moveToFirst()) {
int l_colTitle = l_managedCursor.getColumnIndex(l_projection[0]);
int l_colBegin = l_managedCursor.getColumnIndex(l_projection[1]);
int l_colEnd = l_managedCursor.getColumnIndex(l_projection[2]);
String l_title = String.valueOf(l_colTitle);
String l_begin = Integer.toString(l_colBegin);
String l_end = Integer.toString(l_colEnd);
do {
Map<String, String> map = new HashMap<String, String>();
l_title = l_managedCursor.getString(l_colTitle);
l_begin = getDateTimeStr(l_managedCursor.getString(l_colBegin));
l_end = getDateTimeStr(l_managedCursor.getString(l_colEnd));
map.put("eventTitles", l_title);
map.put("event_begin", l_begin);
map.put("event_end", l_end);
allStudents.add(map);
} while (l_managedCursor.moveToNext());
l_managedCursor.close();
SimpleAdapter adapter = new SimpleAdapter(this, allStudents, R.layout.notice_layout, new String[] { "eventTitles", "event_begin", "event_end" }, new int[] { R.id.tvTitle, R.id.tvBody, R.id.tvTeacherCode});
listViewCalendar.setAdapter(adapter);
}
}
Edit 2:
For some reason the code works fine without this line of code so I've nailed it down to this line of code.
l_end = getDateTimeStr(l_managedCursor.getString(l_colEnd));
Why does the l_colEnd get caught up in an NumberFormatExcetion? When the following line of code could be also caught up in the same NumberFormatException because it is enquiring about the same int format?
l_begin = getDateTimeStr(l_managedCursor.getString(l_colBegin));
Thank you too all who have helped. The other interesting thing also is when I add this
int l_cnt = 0;
do {
++l_cnt;
} while (l_managedCursor.moveToNext() && l_cnt < 100);
to the while clause as shown below at the end of the following code the app works fine with no lines of code throwing a NumberFormatException..
if (l_managedCursor.moveToFirst()) {
int l_cnt = 0;
int l_colTitle = l_managedCursor.getColumnIndex(l_projection[0]);
int l_colBegin = l_managedCursor.getColumnIndex(l_projection[1]);
int l_colEnd = l_managedCursor.getColumnIndex(l_projection[2]);
String l_title = String.valueOf(l_colTitle);
String l_begin = Integer.toString(l_colBegin);
String l_end = Integer.toString(l_colEnd);
do {
Map<String, String> map = new HashMap<String, String>();
l_title = l_managedCursor.getString(l_colTitle);
l_begin = getDateTimeStr(l_managedCursor.getString(l_colBegin));
l_end = getDateTimeStr(l_managedCursor.getString(l_colEnd));
map.put("eventTitles", l_title);
map.put("event_begin", l_begin);
map.put("event_end", l_end);
allStudents.add(map);
++l_cnt;
} while (l_managedCursor.moveToNext() && l_cnt < 100);
Can someone tell me why this code works fine when I fetch and display
the data in certain calendars then in other calendars on my device I
get this NumberFormatException Invalid Long please?
Date l_time = new Date(Long.parseLong(p_time_in_millis));
IMO. This code is "bad" code.
Why? You try to fetch unknown data from unchecked sources
"content://com.android.calendar/events" and "content://calendar/events"
Almost everybody can access calendars and save whatever he like... Sadly there is no rule there for using this! So making a wild guess an app is using this event column to save data in another that your expected format.
Regarding the check l_cnt < 100, where fail stops
It's not failing because the error happens to 101 event or later!
My solution would to check my data, and never trust that other apps will act as I expected or as they should.
So I suggest to change getDateTimeStr method as follows:
public static String getDateTimeStr(String p_time_in_millis) {
SimpleDateFormat sdf = new SimpleDateFormat(DATE_TIME_FORMAT);
long timestamp = 0;
try {
timestamp = Long.parseLong(p_time_in_millis)
} catch(NumberFormatException e) {
Log.w("getDateTimeStr", "Cannot convert '"+p_time_in_millis+"' to long");
e.printStackTrace(); // Prints full error exception
}
Date l_time = new Date(timestamp);
return sdf.format(l_time);
}
Remove the l_cnt < 100 check and leave the code to run checking your logcat! You will now have a better overview of what is happening and also your bad data dates will be 1/1/1970 (due to 0 timestamp) code can be changed responsively in order to handle that dates which does not have the expected format.
Some ideas for handling errors:
Make getDateTimeStr throw an exception to the getEvents() which could catch it and ignore the event with the unexpected data. (Handling logic, ignoring what I cannot understand.)
Recognize the format of the p_time_in_millis in each different case and use different DATE_TIME_FORMAT types regarding the exact format of each event. Okey, that's needs a lot of investigation and still can fail. Also you have to add the case that the format is still unknown so maybe ignore it or use a default value in order not to crash.
Generally, you always try to write a stable app that will not fail if another app saves data in a different format (because it like so or due to its own bug)
Related
I have android application that called information and show it as a list.
I have a spinner when you choose the date from the spinner you get the information related to that date.
In the app first load it calls automatically today information.
this is the code I use in my main activity to create my spinner and fill it with elements and handle the clicks on each item:
// Spinner element
spinner = (Spinner) v.findViewById(R.id.spinner);
// Spinner click listener
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
// On selecting a spinner item
//String item = parent.getItemAtPosition(position).toString();
switch(position){
case 3:
if (JsonUtils.isNetworkAvailable(getActivity())) {
list.clear();
new MyTask().execute(Config.SERVER_URL + "/banko_api.php?d_o=-1");
} else {
Toast.makeText(getActivity(), getResources().getString(R.string.failed_connect_network), Toast.LENGTH_SHORT).show();
}
break;
case 4:
if (JsonUtils.isNetworkAvailable(getActivity())) {
list.clear();
new MyTask().execute(Config.SERVER_URL + "/banko_api.php?d_o=0");
} else {
Toast.makeText(getActivity(), getResources().getString(R.string.failed_connect_network), Toast.LENGTH_SHORT).show();
}
break;
case 5:
if (JsonUtils.isNetworkAvailable(getActivity())) {
list.clear();
new MyTask().execute(Config.SERVER_URL + "/banko_api.php?d_o=1");
} else {
Toast.makeText(getActivity(), getResources().getString(R.string.failed_connect_network), Toast.LENGTH_SHORT).show();
}
break;
default:
if (JsonUtils.isNetworkAvailable(getActivity())) {
list.clear();
new MyTask().execute(Config.SERVER_URL + "/banko_api.php?d_o=0");
} else {
Toast.makeText(getActivity(), getResources().getString(R.string.failed_connect_network), Toast.LENGTH_SHORT).show();
}
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
Calendar calendar = Calendar.getInstance();
Date today = calendar.getTime();
calendar.add(Calendar.DAY_OF_YEAR, -1);
Date yesterday = calendar.getTime();
calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_YEAR, 1);
Date tomorrow = calendar.getTime();
DateFormat dateFormat = new SimpleDateFormat("dd/MM EEE");
String todayAsString = dateFormat.format(today);
String tomorrowAsString = dateFormat.format(tomorrow);
String yesterdayAsString = dateFormat.format(yesterday);
// Spinner Drop down elements
List<String> categories = new ArrayList<String>();
categories.add(yesterdayAsString);
categories.add(todayAsString);
categories.add(tomorrowAsString);
// Creating adapter for spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(getContext(), R.layout.spinner_item, categories);
dataAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
// attaching data adapter to spinner
spinner.setAdapter(dataAdapter);
spinner.setSelection(4);
The problem : first load of the app is calling the data of today (which is the default choice in my spinner) without any problem.
if i choose another element in the spinner it also calls the related data without problem.
now if I want to select back today element in the spinner no data will be brought from the server even when the app at the start up it calls data from the same link and get it.
I get this message in my log :
W/System.err: org.json.JSONException: Value [] of type org.json.JSONArray cannot be converted to JSONObject
The onPostExcute of my Asynktask contains this code:
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (null != progressDialog && progressDialog.isShowing()) {
progressDialog.dismiss();
}
if (null == result || result.length() == 0) {
Toast.makeText(getActivity(), getResources().getString(R.string.failed_connect_network), Toast.LENGTH_SHORT).show();
} else {
try {
Log.d("resultTT",result);
JSONObject mainJson = new JSONObject(result);
JSONArray jsonArray = mainJson.getJSONArray(JsonConfig.CATEGORY_ARRAY_NAME);
JSONObject objJson = null;
for (int i = 0; i < jsonArray.length(); i++) {
objJson = jsonArray.getJSONObject(i);
ItemMatch objItem = new ItemMatch();
objItem.setMatchId(objJson.getString(JsonConfig.Match_ID));
objItem.setMatchTournamentName(objJson.getString(JsonConfig.Match_LEAGUE_NAME));
objItem.setMatchTime(objJson.getString(JsonConfig.Match_TIME));
objItem.setMatchStatus(objJson.getString(JsonConfig.Match_STATUS));
objItem.setMatchLocalTeamName(objJson.getString(JsonConfig.Match_LOCALTEAM_NAME));
objItem.setMatchVisitorTeamName(objJson.getString(JsonConfig.Match_VISITORTEAM_NAME));
objItem.setMatchLocalTeamGoals(objJson.getString(JsonConfig.Match_LOCALTEAM_GOALS));
objItem.setMatchVisitorTeamGoals(objJson.getString(JsonConfig.Match_VISITORTEAM_GOALS));
objItem.setMatchBestOddPercent(objJson.getString(JsonConfig.Match_BEST_ODD_PERCENT));
objItem.setMatchBestOddResult(objJson.getString(JsonConfig.Match_BEST_ODD_RESULT));
list.add(objItem);
}
} catch (JSONException e) {
e.printStackTrace();
}
for (int j = 0; j < list.size(); j++) {
object = list.get(j);
array_match_id.add(String.valueOf(object.getMatchId()));
str_match_id = array_match_id.toArray(str_match_id);
array_league_name.add(String.valueOf(object.getMatchTournamentName()));
str_league_name = array_league_name.toArray(str_league_name);
array_match_time.add(String.valueOf(object.getMatchTime()));
str_match_time = array_match_time.toArray(str_match_time);
array_match_status.add(String.valueOf(object.getMatchStatus()));
str_match_status = array_match_status.toArray(str_match_status);
array_match_localteam_name.add(object.getMatchLocalTeamName());
str_match_localteam_name = array_match_localteam_name.toArray(str_match_localteam_name);
array_match_visitorteam_name.add(object.getMatchVisitorTeamName());
str_match_visitorteam_name = array_match_visitorteam_name.toArray(str_match_visitorteam_name);
array_match_localteam_goals.add(object.getMatchLocalTeamGoals());
str_match_localteam_goals = array_match_localteam_goals.toArray(str_match_localteam_goals);
array_match_visitorteam_goals.add(object.getMatchVisitorTeamGoals());
str_match_visitorteam_goals = array_match_visitorteam_goals.toArray(str_match_visitorteam_goals);
array_match_best_odd_percent.add(object.getMatchBestOddPercent());
str_match_best_odd_percent = array_match_best_odd_percent.toArray(str_match_best_odd_percent);
array_match_best_odd_result.add(object.getMatchBestOddResult());
str_match_best_odd_result = array_match_best_odd_result.toArray(str_match_best_odd_result);
}
setAdapterToListView();
}
In the try section of this code u can see I make a log of the result to see what is coming from the server i just get this : D/resultTT: []
and as you see the try is inside the else section so in the if statement of this section i check if the result is null or empty ; but the code passes it and enter the else statement but still showing that the returned result array is empty.
I want some help to find the reason behind this empty returned array even it loads fine at the start up. why can not it get the information after I choose any element in the spinner and then come back to the default (today) element?
UPDATE : this is my php side-server api code
<?php
include_once ('includes/variables.php');
DEFINE ('DB_HOST', $host);
DEFINE ('DB_USER', $user);
DEFINE ('DB_PASSWORD', $pass);
DEFINE ('DB_NAME', $database);
$mysqli = #mysql_connect (DB_HOST, DB_USER, DB_PASSWORD) OR die ('Could not connect to MySQL');
#mysql_select_db (DB_NAME) OR die ('Could not select the database');
?>
<?php
mysql_query("SET NAMES 'utf8'");
$date_offset = mysql_real_escape_string($_GET[d_o]);
//$date_offset = 0;
if(empty($date_offset) || $date_offset == "0")
{
$date_offset_value = "0";
$query="SELECT a.*, m.match_id, m.match_time, m.en_tournament_name FROM app_banko a inner join matches_of_comments m on m.match_id = a.match_id where a.date_offset = $date_offset_value limit 20";
$resouter = mysql_query($query);
}
else
{
$date_offset_value = $date_offset;
$query="SELECT a.*, m.match_id, m.match_time, m.en_tournament_name FROM app_banko a inner join matches_of_comments m on m.match_id = a.match_id where a.date_offset = $date_offset_value limit 20";
$resouter = mysql_query($query);
}
$set = array();
$total_records = mysql_num_rows($resouter);
if($total_records >= 1){
while ($link = mysql_fetch_array($resouter, MYSQL_ASSOC)){
$set['NewsApp'][] = $link;
}
}
echo $val= str_replace('\\/', '/', json_encode($set));
?>
If you get an array in return when expecting an object, there might be something wrong with the request to the API. One way is to figure it out it set up Wireshark on the development machine to sniff and filter the traffic. Then you can see if your request is faulty.
It is possible that the value of the response argument from the onPostExecute method contains stringified JSONArray, not JSONObject.
You can always test this with:
try:
JSONArray jsonArray = new JSONArray(result);
catch(JSONException e) {
// String `result` is not an array. Parse it as a regular JSONObject.
}
Testing wheter string is an empty json array (depends on it's formatting, especially when it may contain some white characters) checking it's length might be a pretty bad idea.
It all depends how are determined an API endpoints that you are calling.
One more tip at the end. If you are planning to consume REST API I strongly recommend using:
Retrofit - which allows you to easily define interfaces to access your API,
GSON - to automatically convert responses for Java models.
Your result string is an empty array but not an empty string. The empty array is represented as the following string:
String result = "[]";
In that case result.length() is equal to 2.
When parsing JSON you need to know if the parsed object is of type Object or of type Array. The former one is wrapped with braces {}, the later one with square brackets [].
So the following line:
JSONObject mainJson = new JSONObject(result);
Should probably be:
JSONArray mainJson = new JSONArray(result);
But I cannot emphasize enough that you need to know what your API returns if you want to be able to parse it correctly.
EDIT:
Well, json_encode will have a hard time to guess whether it should create a JSON Array or a JSON Object out of the empty array that you created with $set = array();.
Adding objects to the array like you do in your loop makes it obvious for json_encode that it should create a JSON Object.
I don't know if you can force json_encode's behavior, but worst case you could check yourself if the array is empty and return "" or null if the array is empty.
$set = array();
$total_records = mysql_num_rows($resouter);
if ($total_records >= 1) {
while ($link = mysql_fetch_array($resouter, MYSQL_ASSOC)) {
$set['NewsApp'][] = $link;
}
echo $val= str_replace('\\/', '/', json_encode($set));
} else {
echo $val="";
}
please put a check result.isEmpty() in your try block condition may this could solve your problem.
you can not directly get response in string . it can use JSONObject and JSONArray.
I have an empty list. I fill it with my class's instances in a loop. And right after adding an instance, I retrieve the last element and check its parameters. The values of parameters are fine.
Now, when I have filled all the values and control gets out of the loop, the date and time (which are instances of Calendar) of all the elements of that list are somehow replaced with the very last element's date and time, whereas the rest of parameters remain the same. I don't know if there is a logical error in my code or there is a bug in Android Studio.
I am printing out the values to Logcat, before entering the element and after entering that element. The values are same. But when the control reaches cursor.close(), all elements in that list are replaced.
public List<YearChart> readYearChart() throws Exception {
List<YearChart> yearChart = null;
SimpleDateFormat dateFormat = TheApplication.getDateFormat();
SimpleDateFormat timeFormat = TheApplication.getTimeFormat();
Cursor cursor = sqLiteDatabase.query(MyDatabaseHelper.table_YearChart, super.columnsToRetrieve, null, null, null, null, null);
if(cursor.moveToFirst()) {
yearChart = new ArrayList();
int id;
Calendar date = Calendar.getInstance();
int namazId;
Calendar time = Calendar.getInstance();
int i=0;
do
{
id = cursor.getInt(cursor.getColumnIndex(super.columnsToRetrieve[0]));
String dateStr = cursor.getString(cursor.getColumnIndex(super.columnsToRetrieve[1]));
namazId = cursor.getInt(cursor.getColumnIndex(super.columnsToRetrieve[2]));
String timeStr = cursor.getString(cursor.getColumnIndex(super.columnsToRetrieve[3]));
if(!dateStr.isEmpty() && !timeStr.isEmpty())
{
date.setTime(dateFormat.parse(dateStr));
time.setTime(timeFormat.parse(timeStr));
YearChart yc = new YearChart(id, date, namazId, time);
Log.v("YearChart_ID >", String.valueOf(yc.getId()));
Log.v("YearChart_Date>", TheApplication.getDateFormat().format(yc.getDate().getTime()));
Log.v("YearChart_NID >", String.valueOf(yc.getNamazId()));
Log.v("YearChart_Time>", TheApplication.getTimeFormat().format(yc.getTime().getTime()));
Log.v("*****", "*****");
yearChart.add(yc);
YearChart yc1 = yearChart.get(i);
Log.v("YearChart_ID >", String.valueOf(yc1.getId()));
Log.v("YearChart_Date>", TheApplication.getDateFormat().format(yc1.getDate().getTime()));
Log.v("YearChart_NID >", String.valueOf(yc1.getNamazId()));
Log.v("YearChart_Time>", TheApplication.getTimeFormat().format(yc1.getTime().getTime()));
Log.v("*****", "*****");
i++;
}
} while (cursor.moveToNext());
}
cursor.close();
return yearChart;
}
I am using Android Studio (v1.1.0).
You're passing the same reference to date and time - meaning each element in the list holds a reference to those exact objects. When you call date/time methods, you'll be updating those two variables which all your list items point to.
The solution is to move the instantiation of date and time into the do-while loop.
I'm trying to add words to user dictionary in bulks (tens of thousands of words).
I've tried to
Scanner scanner = new Scanner(file);
int counter = 0;
while(scanner.hasNextLine()) {
String word = scanner.nextLine();
UserDictionary.Words.addWord(getBaseContext(), word, 255, null, Locale.getDefault());
setProgress((float) counter++ * 100 / linesCount);
}
and I've also tried bulkinsert
ArrayList<String> words = new ArrayList<String>(capacity);
int counter = 0;
while(scanner.hasNextLine()) {
words.add(scanner.nextLine());
if (words.size() >= capacity) {
MyUserDictionary.addWords(getBaseContext(), words, Locale.getDefault());
words.clear();
setProgress((float) counter * 100 / linesCount);
}
counter++;
}
if (!words.isEmpty()) {
MyUserDictionary.addWords(getBaseContext(), words, Locale.getDefault());
}
And I've tried applyBatch.
All this method results with very long running time.
I know that sqlite can do better with transactions.
Do you know more faster way to do it?
EDIT1:
final ContentResolver resolver = context.getContentResolver();
final int COLUMN_COUNT = 5;
List<ContentValues> valueses = new ArrayList<ContentValues>(words.size());
for (String word: words) {
ContentValues values = new ContentValues(COLUMN_COUNT);
values.put(UserDictionary.Words.WORD, word);
values.put(UserDictionary.Words.FREQUENCY, DEFAULT_FREQUENCY);
values.put(UserDictionary.Words.LOCALE, null == locale ? null : locale.toString());
values.put(UserDictionary.Words.APP_ID, 0); // TODO: Get App UID
values.put(UserDictionary.Words.SHORTCUT, "");
valueses.add(values);
}
resolver.bulkInsert(UserDictionary.Words.CONTENT_URI, valueses.toArray(new ContentValues[valueses.size()]));
I have read several posts here on speed issues when looping through a cursor and tried the answers given in these posts such as e.g. do not use getcolumnindex in the loop call this once etc.
However with a database having around 2400 records it takes around 3 to 5 minutes to finish.
The loop is running in an async task method so that it does not hang up the device and the database is handled via a database adapter.
The loop code is as follows :
while (!exportrec.isAfterLast()) {
if ( exportrec.moveToNext() ) {
fulldate = exportnumberformatter(exportrec.getInt(daye))
+"/"+exportnumberformatter(exportrec.getInt(monthe))+"/"
+String.valueOf(exportrec.getInt(yeare));
fulltime = exportnumberformatter(exportrec.getInt(houre))+":"
+exportnumberformatter(exportrec.getInt(mine))+":"
+exportnumberformatter(exportrec.getInt(sece));
noiseid = exportrec.getInt(typee);
exportedinfo += exporttypes[id] +","+exportrec.getString(notee)+","+
fulldate+","+fulltime+" \n" ;
}
}
The exportnumberformatter does the following :
public String exportnumberformatter(int i) {
String result = Integer.toString(i);
if (result.length() >1 ) {
return Integer.toString(i);
}
String zeroprefix = "";
zeroprefix = "0"+result;
return zeroprefix ;
}
The cursor is called as follows before the loop to get the data :
exportrec = MD.GetAllLogs(2, "date_sort");
exportrec.moveToFirst();
The MD is the database adapter and the GetAllLogs Method (this has been played with to try and speed things up and so the date_sort that is used is really ignored here):
public Cursor GetAllLogs(Integer i,String sortfield)
{
String sorted = "";
if (i == 1 ) {
sorted = "DESC";
} else if (i == 2) {
sorted = "ASC";
}
return mDB.query(DB_TABLE, new String[] {COL_ID, COL_TYPE,COL_IMAGE, COL_INFO,COL_IMAGE,COL_HOUR,COL_SEC,COL_MIN,COL_DAY,COL_MON,COL_YEAR,COL_SORT_DATE},
null, null, null, null, COL_ID+" "+sorted);
}
When I created the table in the database it had no indexes so I created these via the upgrade method. However they did not error or appear to fail when I did this but what I do not know is A) does the database/table need rebuilding after an index is created and B) how to tell if they have been created ? the two indexes were based on the ID as the first and a field that holds the year month day hour minute second all in on Long Integer.
I am concerned that the loop appears to be taking this long to read through that many records.
Update:
rtsai2000's and the suggestion from CL answer has improved the speed from minutes to seconds
Your exportedInfo String is growing and growing. Save the results in an array and Stringify later (such as with StringBuilder).
You are not closing your cursor after reading the records.
List<String> exportedInfo = new ArrayList<String>();
Cursor exportrec = GetAllLogs();
try {
while (exportrec.moveToNext()) {
String info = String.format("%s, %s, %02d/%02d/%02d, %02d:%02d:%02d",
exporttypes[id],
exportrec.getString(notee),
exportrec.getInt(daye),
exportrec.getInt(monthe),
exportrec.getInt(yeare),
exportrec.getInt(houre),
exportrec.getInt(mine),
exportrec.getInt(sece));
exportedInfo.add(info);
}
} finally {
exportrec.close();
}
return exportedInfo;
There was some XML parsed text that looked like this:
06:00 Vesti<br>07:15 Something Else<br>09:10 Movie<a href="..."> ... <br>15:45 Something..
and there was a lot of it..
Well, I have done this:
String mim =ses.replaceAll("(?s)\\<.*?\\>", " \n");
there was no other way to show text nicely.
Now, after few showings, and some time, I need that same text separated into alone strings like this:
06:00 Vesti
... or
07:15 Something Else
I've tried something like this, but it does not work:
char[] rast = description.toCharArray();
int brojac = 0;
for(int q=0; q<description.length(); q++){
if(rast[q]=='\\' && rast[q+1]=='n' ) brojac++;
}
String[] niz = new String[brojac];
int bf1=0;
int bf2=0;
int bf3=0;
int oo=0;
for(int q=0; q<description.length(); q++){
if(rast[q]=='\\'&& rast[q+1]=='n'){
bf3=bf1;
bf1=q;
String lol = description.substring(bf3, bf1);
niz[oo]=lol;
oo++;
}
}
I know that in description.substring(bf3,bf1) are not set as they should be but I think that this:
if(rast[q]=='\\' && rast[q+1]=='n)
does not work that way.. is there any other solution?
Note. there is no other way to get that resource. , It must be through this.
Calling Html.fromHtml(String) will properly translate the <br> into \n.
String html = "06:00 Vesti<br>07:15 Something Else<br>09:10 Movie<a href=\"...\"> ... <br>15:45 Something..";
String str = Html.fromHtml(html).toString();
String[] arr = str.split("\n");
Then, just split it on a line basis - no need for regexps (which you shouldn't be using to parse HTML in the first case).
Edit: Turning everything into a bunch of Dates
// Used to find the HH:mm, in case the input is wonky
Pattern p = Pattern.compile("([0-2][0-9]:[0-5][0-9])");
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm");
SortedMap<Date, String> programs = new TreeMap<Date, String>();
for (String row : arr) {
Matcher m = p.matcher(row);
if (m.find()) {
// We found a time in this row
ParsePosition pp = new ParsePosition(m.start(0));
Date when = fmt.parse(row, pp);
String title = row.substring(pp.getIndex()).trim();
programs.put(when, title);
}
}
// Now programs contain the sorted list of programs. Unfortunately, since
// SimpleDateFormat is stupid, they're all placed back in 1970 :-D.
// This would give you an ordered printout of all programs *AFTER* 08:00
Date filter = fmt.parse("08:00");
SortedMap<Date, String> after0800 = programs.tailMap(filter);
// Since this is a SortedMap, after0800.values() will return the program names in order.
// You can also iterate over each entry like so:
for (Map.Entry<Date,String> program : after0800.entrySet()) {
// You can use the SimpleDateFormat to pretty-print the HH:mm again.
System.out.println("When:" + fmt.format(program.getKey()));
System.out.println("Title:" + program.getValue());
}
Use regex:
List<String> results = new ArrayList<String>();
Pattern pattern = Pattern.compile("(\d+:\d+ \w+)<?");
Matcher matcher = pattern.matcher("06:00 Vesti<br>07:15 Something Else<br>09:10 Movie<a href="..."> ... <br>15:45 Something..");
while(matcher.find()) {
results.add(matcher.group(0));
}
results will end up as a list of strings:
results = List[
"06:00 Vesti",
"07:15 Something Else",
"09:10 Movie",
"15:45 Something.."]
See Rexgex Java Tutorial for an idea of how javas regex library works.