I have different screens for different entities which are Products, Rooms, Posts, and, Users.
All of them have distinct ID which I use to open the particular screen to try to load the data from the ID parameter passed on the relevant screen/activity via the APIs.
The mechanism I thought for Products,Rooms,and Posts in particular are that on Notifications Screen and alike, I want to send coded or tagged string; like below for Products for example:
You have bid on <p244 24LED Lampshade />
And to match the above I have a regular expression:
<p([0-9]*)\s(.*?)\/>(\s|$)
Here's a sample string:
String dummyText = "Hi #dan we product test <p1337 product />" +
"\n how about <r123 Room name/> is a nice room" +
"\n what <t234 this post details more about it/> but you should " +
"\n #poprocks woah one #sad";
It seems to work fine with single use of the product/post/room, but it messes up with more instances of the coded/tagged string.
But like I stated, with multiple instances like the following test:
String dummyText = "Hi #dan we product test <p1337 product /> and were more happy with <p53 car/> " +
"\n eh <r123 Room name/> is a nice room and <r233 dans house/> sucked while <r123 fun time/> was ok " +
// "\n what <t234 this post details more about it/> but you should " +
"\n <t234 view this as well/>" +
"\n #poprocks woah one #sad";
It messes up:
Here's my entire code process:
String dummyText = "Hi #dan we product test <p1337 product /> and were more happy with <p53 car/> " +
"\n eh <r123 Room name/> is a nice room and <r233 dans house/> sucked while <r123 fun time/> was ok " +
// "\n what <t234 this post details more about it/> but you should " +
"\n <t234 view this as well/>" +
"\n #poprocks woah one #sad";
List<Pattern> patternsList = new ArrayList<>();
patternsList.add(Pattern.compile(REGEX_NOTI_ROOMS)); //0
patternsList.add(Pattern.compile(REGEX_NOTI_PRODUCTS)); //1
patternsList.add(Pattern.compile(REGEX_NOTI_TWEETS)); //2
patternsList.add(Pattern.compile(REGEX_NOTI_MENTION)); //3
patternsList.add(Pattern.compile(REGEX_ARABIC_N_NUM_HASHTAG)); //4
holder.row_noti_messageTV.setText(makeSpannable(dummyText, patternsList));
holder.row_noti_messageTV.setMovementMethod(new PkMovementMethod());
Where the relevant regex are:
public static final String REGEX_NOTI_ROOMS ="<r([0-9]*)\\s(.*?)\\/>(\\s|$)";
public static final String REGEX_NOTI_PRODUCTS ="<p([0-9]*)\\s(.*?)\\/>(\\s|$)";
public static final String REGEX_NOTI_TWEETS ="<t([0-9]*)\\s(.*?)\\/>(\\s|$)";
public static final String REGEX_ARABIC_N_NUM_HASHTAG ="#(\\w*[0-9a-zA-Zء-ي٠-٩]+\\w*[0-9a-zA-Zء-ي٠-٩])";
public static final String REGEX_NOTI_MENTION ="(?:^|\\s|$|[.])#[\\p{L}0-9_]*";
And my makeSpannable method is:
public SpannableStringBuilder makeSpannable(String rawText, List<Pattern> listofPatterns) {
// StringBuffer sb = new StringBuffer();
SpannableStringBuilder spannable = new SpannableStringBuilder(rawText);
for(int i=0; i<listofPatterns.size(); i++)
{
Matcher matcher = null;
if(i==0) //init only
matcher = listofPatterns.get(i).matcher(rawText);
else
matcher = listofPatterns.get(i).matcher(spannable);
while (matcher.find()) {
showLogMessage("jsonParse", "hit on iteration" + i + " group == " + matcher.group());
if(i==3 || i == 4)
{
try {
String abbr = matcher.group();
showLogMessage("jsonParse", "loop[3 | 4 are normal] == " + i + " group(0) == " + abbr);
int start = matcher.start();
int end = matcher.end();
NotificationSpan ourSpan = new NotificationSpan(Color.BLUE, Color.RED, Color.TRANSPARENT, new IdTitleStore(abbr, abbr, abbr), NotificationAdapter.this);
spannable.setSpan(ourSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
e.printStackTrace();
}
}
else if(i<=2) {
try {
String orgGroup = matcher.group();
// get the match
String abbr = matcher.group(2);
showLogMessage("jsonParse", "loop == " + i + " group2 == " + abbr);
int startPoint = matcher.start();
int endPoint = matcher.end();
NotificationSpan ourSpan = new NotificationSpan(Color.RED, Color.BLUE, Color.TRANSPARENT, new IdTitleStore(matcher.group(1), abbr, orgGroup), NotificationAdapter.this);
Spannable spanText = new SpannableString(abbr);
spanText.setSpan(
ourSpan, 0, abbr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
spannable.replace(startPoint, endPoint, spanText);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return spannable;
}
Note: NotificationSpan is a custom span I use to store the group(1) as it has the ID and from group(0) I can deduce on click whether it may be a Post, Product, or a Room entity to open it.
Any feedback shall be appreciated, even if it can point me towards the right direction. Like if my approach in itself is fundamentally wrong or something, please do let me know.
EDIT: Someone pointed out at comments to remove the redundant (\s|$) from the Regular Expressions, and it did seemingly nothing
Logs for the dummyString I tested:
String dummyText = "Hi #dan we product test <p1337 product /> and were more happy with <p53 car/> " +
"\n eh <r123 Room name/> is a nice room and <r233 dans house/> sucked while <r123 fun time/> was ok " +
"\n what <t233 this post details more about it/> but you should " +
"\n <t234 view this as well/>" +
"\n #poprocks woah one #sad";
E/jsonParse: hit on iteration0 group(0) == <r123 Room name/>
E/jsonParse: hit on iteration0 group(0) == <r233 dans house/>
E/jsonParse: hit on iteration0 group(0) == <r123 fun time/>
E/jsonParse: hit on iteration1 group(0) == <p1337 product />
E/jsonParse: hit on iteration1 group(0) == <p53 car/>
E/jsonParse: hit on iteration2 group(0) == <t234 view this as well/>
E/jsonParse: hit on iteration3 group(0) == #dan
E/jsonParse: hit on iteration4 group(0) == #poprocks
E/jsonParse: hit on iteration4 group(0) == #sad
It is also weird that the first instance is not detected by the matcher at all.
i.e
"\n what <t234 this post details more about it/> but you should "
It may entirely be possible that something is wrong with the logic itself of the Multiple Patterns being matched inside loops, but I really can't seem to figure it out. Appreciate the comment though!
EDIT EDIT*: I think I finally understand what the problem was/is. Adding dot after the replace method it gave me two suggestions, notify() and notifyAll(), which got me wondering this is indeed multi-thread based operation (sort of obvious to others but yeah!). So the multiple loop was in fact the issue.
Since replacing a call updates the span itself, the inner loop (while mathcer.find()) did not have the latest span on the matcher, it had different/previous one, which would've worked fine if there were only one instance found, but since in case of multiple the start and end were way off and hence some unintended stuff was happening. Followings the updated code, I did keep the (\s|$) just in case a Product/Post/Room is the end of the string so it does match and not remain blank.
public SpannableStringBuilder makeSpannable(String rawText, List<Pattern> listofPatterns) {
SpannableStringBuilder spannable = new SpannableStringBuilder(rawText);
Matcher matcher = null;
for(int i=0; i<listofPatterns.size(); i++)
{
matcher = listofPatterns.get(i).matcher(spannable.toString());
while (matcher.find()) {
showLogMessage("jsonParse", "hit on iteration" + i + " group == " + matcher.group());
if(i<=2) {
try {
String orgGroup = matcher.group();
// get the match
String abbr = matcher.group(2);
showLogMessage("jsonParse", "span txt of iteration " + i + " going to be group2 == " + abbr);
int startPoint = matcher.start();
int endPoint = matcher.end();
NotificationSpan ourSpan = new NotificationSpan(Color.RED, Color.BLUE, Color.TRANSPARENT, new IdTitleStore(matcher.group(1), abbr, orgGroup), NotificationAdapter.this);
Spannable spanText = new SpannableString(abbr);
spanText.setSpan(
ourSpan, 0, abbr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
spannable.replace(startPoint, endPoint-1, spanText);
matcher = listofPatterns.get(i).matcher(spannable);
} catch (Exception e) {
e.printStackTrace();
}
}
else {
try {
String abbr = matcher.group();
showLogMessage("jsonParse", "span txt of iteration " + i + " going to be group(0) == " + abbr);
int start = matcher.start();
int end = matcher.end();
NotificationSpan ourSpan = new NotificationSpan(Color.BLUE, Color.RED, Color.TRANSPARENT, new IdTitleStore(abbr, abbr, abbr), NotificationAdapter.this);
spannable.setSpan(ourSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return spannable;
}
Additional note: I think it'd be better if I explain why I've divided the loop into two parts to begin-with as well. The reason is simple, first 3 of my REGEX I 100% know for sure have group(2) elements, which I have implemented the click ID mechanism of. The last two are normal hashtag and mention ones which don't have group(2).
Here's the final working look, hope I don't face any performance issues:
Related
I am working on an Android Application which saves data to an SQLite database. I've removed the first piece of code as I believe the second piece of code is already doing the same thing. I have run a few tests and everything still seems to be working perfectly. Is there any further purpose for the first piece of code?
First piece of code....
Cursor res = myDb.getRoutineForCurrentDay(currentDay);
if (res.getCount() == 0) {
} else {
//data found, show on screen
StringBuffer buffer = new StringBuffer();
while (res.moveToNext()) {
buffer.append("Id : " + res.getString(0) + "\n");
buffer.append("Day : " + res.getString(1) + "\n");
buffer.append("Act : " + res.getString(2) + "\n");
buffer.append("Slot : " + res.getString(3) + "\n");
}
}
ImageID = 0;
break;
Second piece of code....
private void getRoutine() {
Cursor res = myDb.getRoutineForCurrentDay(currentDay);
if (res.getCount() == 0) {
} else {
//data found, show on screen
while (res.moveToNext()) {
int ActID = res.getInt(2);
int SlotID = res.getInt(3);
ImageView slot = (ImageView) findViewById(SlotID);
slot.setImageResource(ActID);
}
}
Well, the second piece of code sets up an Imageview and populates it, while the first piece of code only processes the info as text.
My guess would be someone wrote the first piece of code just to check whether or not the local DB contains the correct values.
The second snippet should be all you need.
I want to replace one word in the String by using substring. But it seen didn't work.
for example: The string is 0000 , and I want to replace the first word from 0 to 1.
It should be 1000. but it doesn't.
The code is like the following
String WorkStatus = "0000";
if(WorkStatus.substring(0, 1).matches("0"))
{
WorkStatus.substring(0, 1).replace("0", "1");
Log.d(TAG, "WorkStatus.substring(0, 1) = " + WorkStatus.substring(0, 1) + "\n");
Log.d(TAG, "WorkStatus = " + WorkStatus + "\n");
}
It didn't work , the string always show 0000. And what I want is "1000"
Do I missing something ?
use this
String WorkStatus = "0000";
//You use matches, while you might as well use equals
if (WorkStatus.substring(0, 1).equals("0")) {
//reassign workstatus to workstatus where the first entry is a '1' + the last three chars "000"
WorkStatus = WorkStatus.substring(0, 1).replace("0", "1") + WorkStatus.substring(1, WorkStatus.length());
Log.d(TAG, "WorkStatus.substring(0, 1) = " + WorkStatus.substring(0, 1) + "\n");
Log.d(TAG, "WorkStatus = " + WorkStatus + "\n");
}
You didnt assign the modified string to WorkStatus
Another possibility is converting the string to a char[] and replacing the index, instead of working with substrings.
String WorkStatus = "0000";
char[] chars = WorkStatus.toCharArray();
if (chars[0] == '0') {
chars[0] = '1';
WorkStatus = new String(chars);
}
If you want other chars to become 1 instead of zero, alter the chars[0] into chars[index], where index is the index you want to change from 0 to 1
Or, even easier, use a StringBuilder:
int yourIndex = 2; //your index which you want to check for 0 and change to 1
StringBuilder sb = new StringBuilder("0000");
if (sb.charAt(yourIndex) == '0')
sb.setCharAt(yourIndex, '1');
WorkStatus = sb.toString();
method replace has a return value of the string after replaced
you shuold resign the result to the String
WorkStatus=WorkStatus.substring(0, 1).replace("0", "1")+ WorkStatus.substring(1, WorkStatus.length();
if you asign it to a new variable like the below code, you can get what you needed.
String newWorkStatus=WorkStatus.substring(0, 1).replace("0", "1")+WorkStatus.substring(1);
Log.d("LOG", "WorkStatus.substring(0, 1) = " + WorkStatus.substring(0, 1) + "\n");
Log.d("LOG", "WorkStatus = " + WorkStatus + "\n");
Log.d("LOG", "New WorkStatus = " + newWorkStatus + "\n");
WorkStatus.substring(0, 1).replace("0", "1"); returns 1, you should use StringBuilder instead of String.
My solution:
StringBuilder WorkStatus = new StringBuilder("0000");
int pos = WorkStatus.indexOf("0", 0);
if (pos != -1) {
WorkStatus.replace(pos, pos + 1, "1");
}
System.out.print(WorkStatus);
I want to insert a log in LogCat that when I click on it jumps to its line like some error logs that are generated by system.
Is it possible?
I found it:
public static void showLogCat(String tag, String msg) {
StackTraceElement[] stackTraceElement = Thread.currentThread()
.getStackTrace();
int currentIndex = -1;
for (int i = 0; i < stackTraceElement.length; i++) {
if (stackTraceElement[i].getMethodName().compareTo("showLogCat") == 0)
{
currentIndex = i + 1;
break;
}
}
String fullClassName = stackTraceElement[currentIndex].getClassName();
String className = fullClassName.substring(fullClassName
.lastIndexOf(".") + 1);
String methodName = stackTraceElement[currentIndex].getMethodName();
String lineNumber = String
.valueOf(stackTraceElement[currentIndex].getLineNumber());
Log.i(tag, msg);
Log.i(tag + " position", "at " + fullClassName + "." + methodName + "("
+ className + ".java:" + lineNumber + ")");
}
Its usage:
showLogCat("tag", "message");
The important thing is to insert "(X:Y)" in your log message, while X is your desired file name and Y is your desired line number in X. (I learned it from #breceivemail's answer). So try:
public static void log(final String tag, final String msg) {
final StackTraceElement stackTrace = new Exception().getStackTrace()[1];
String fileName = stackTrace.getFileName();
if (fileName == null) fileName=""; // It is necessary if you want to use proguard obfuscation.
final String info = stackTrace.getMethodName() + " (" + fileName + ":"
+ stackTrace.getLineNumber() + ")";
Log.LEVEL(tag, info + ": " + msg);
}
Note: The LEVEL is the log level and can be v, d, i, w, e or wtf.
Now you can use log(tag, msg) instead of Log.LEVEL(tag, msg).
Example:
MainActivity.java:
...
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
log("Test Tag", "Hello World!");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
...
The output:
12-30 14:24:45.343 ? I/Test Tag: onCreate (MainActivity.java:10): Hello World!
And MainActivity.java:10 automatically would be a link and you can click on it!
You can also assign following value to info variable if you want more verbose log:
final String info = stackTrace.getClassName() + "." + stackTrace.getMethodName() + " ("
+ fileName + ":" + stackTrace.getLineNumber() + ")\n";
So the output of above example would be:
12-30 14:33:07.360 ? I/Test Tag: com.example.myapp.MainActivity.onCreate (MainActivity.java:11)
Hello World!
Please use this Tree with Timber.
class MyLinkingTimberTree : Timber.DebugTree() {
override fun createStackElementTag(element: StackTraceElement): String? {
return makeClickableLineNumber(element)
}
private fun makeClickableLineNumber(
element: StackTraceElement
): String {
val className = element.fileName
val methodName = element.methodName
val lineNumber = element.lineNumber
val fileName = element.fileName
val stringBuilder = StringBuilder(className)
.append(".")
.append(methodName)
.append(" (")
.append(fileName)
.append(":")
.append(lineNumber)
.append(") ")
return stringBuilder.toString()
}
}
And then just instantiate it like this:
class MyApplication: Application() {
override fun onCreate() {
super.onCreate()
if(BuildConfig.DEBUG) {
Timber.plant(MyLinkingTimberTree())
}
}
}
Then just use Timber normally:
Timber.d("Currently Signed in:")
And this is the result. Nice, isn't it? I hope you enjoy using it as much as I enjoyed making it! ;)
Yes you can do it .. Follow the example as answered on SO - logging
To answer the question in a simple way:
respecter cette règle :
{FileName}.{ext}:{LigneNumber}
e.g. MainActivity.java:10
which gives a sample as below
Log.d(TAG, "onResume: MainActivity.java:10");
I hope this will help you
This isn't exactly an answer to the question, but perhaps it's a "close enough" workaround.
Highlight the log text
Press CTRL-SHIFT-F
Double-Click on the search result.
If the text is highlighted before you press CTRL-SHIFT-F, then you don't need to type or copy/paste it in.
If your searches tend to produce too many results, you can use live templates to make unique logcat entries:
Create a live template to insert the Class, Method, and Line-Number (at the time of writing). I use "logi." Yes, the line number will become less and less accurate as you continue to write, but it can still function as a way to make your log entries more "findable."
I am having a string(number) with special characters. I want to search for a sub-string(comprising of digits only) & also I want to detect the starting index & ending index of matching sub-string in the string.
For example: main string: (+91)-1231212 1231
Sub-string to search: 1212
Currently I am using the following code to do this but in place of 1212,it searched for 12312. For other cases, it works fine.
String sss0 = "1212";
String sss1 = "(+91)-1231212 1231";
sss0 = sss0.replaceAll("[^\\d]","");
System.out.println("*************************"+sss0);
String ptn = "" + sss0.charAt(0);
for(int jj=0; jj<sss0.length()-1; jj++){
ptn += "[^" + sss0.charAt(jj) + sss0.charAt(jj+1) + "]*?" + sss0.charAt(jj+1);
}
System.out.println("ptn: " + ptn);
Pattern p300 = Pattern.compile(ptn);
Matcher m300 = p300.matcher(sss1);
if(m300.find()){
System.out.println("start, stop: " + m300.start() + "," + (m300.end()-1 ));
System.out.println("substring: " + sss1.substring(m300.start(), m300.end()));
}
Please help me. Thanks in advance.
Try this :
int start = sss1.indexOf(sss0);
if(start != -1) {
System.out.println("Start : " + start);
System.out.println("End : " + start.length()); //maybe add +1 here depending on what you mean by end index.
}
You can also put this in a loop to find all occurences of the substring.
pseudocode:
pattern = ""
foreach char c in sss0:
pattern += c + "[^0-9]*"
found_substring = match(pattern, sss1)
the idea being to intersperse the literal characters you're looking for with the pattern that you're willing to skip over.
I am trying to pass two variables from one screen to another. From the previous screeen you click a button, 1 or 2 and it passes that value on. It also passes the value 2 as the correct value. I know they are both working as I output each variable on the next screen. Here is the code. It always outputs wrong though.
Intent i = getIntent();
Bundle b = i.getExtras();
String newText = b.getString("PICKED");
String correct = b.getString("CORRECT");
TextView titles = (TextView)findViewById(R.id.TextView01);
if(newText == correct){
titles.setText("Correct" + newText + " " + correct + "");
}
else{
titles.setText("Wrong" + newText + " " + correct + "");
}
because you are not comparing the string. you are comparing if both are pointing to same object.
to compare string use
if(nexText.equals(correct))
if(newText == correct)
This will always be false. To compare the contents of two Strings character by character, use the .equals method:
if( newText.equals(correct) )
Using == on objects in Java means you are comparing the values of the memory address stored in these pointers/references. Since they are different String objects, they will never have the same address.
You don't compare Strings this way, rewrite code this way to get things done:
Intent i = getIntent();
Bundle b = i.getExtras();
String newText = b.getString("PICKED");
String correct = b.getString("CORRECT");
TextView titles = (TextView)findViewById(R.id.TextView01);
if(newText.equals(correct)){
titles.setText("Correct" + newText + " " + correct + "");
}
else{
titles.setText("Wrong" + newText + " " + correct + "");
}