I am trying to use contains for strings coinciding with the search symbols. However, seems like contains does not have an ignore case unlike equals. Is there any way to go around ?
The following line of code is where I am using the same (I have heard of pattern, but how do I use the same in my case? )
searchSymbol.contains(mSearchView.getText().toString()
Thanks!
Justin
You can just convert them both to lower case and use contains() as normal:
searchSymbol.toLowerCase().contains(mSearchView.getText().toString().toLowerCase())
You could write your own function to do this if you want to keep it clean:
public static boolean containsIgnoreCase(String haystack, String needle){
return haystack.toLowerCase().contains(needle.toLowerCase());
}
You could use the function from StringUtils:
org.apache.commons.lang3.StringUtils.containsIgnoreCase("testString", "stSt");
In any case, you're going to want to watch out for unicode characters. They don't play by the normal rules of "case" in most circumstances.
Related
Right now I am starting a new project and I usually had a constant class for symbols like:
object Symbols{
const val CHAR_COLON = ":"
const val CHAR_COMMA = ","
const val CHAR_SEMICOLON = ";"
etc.
}
Would be great if a class like this was already added in Java or Kotlin but I don't seem to find anything like this. Does anyone know of such a thing? Thanks.
I'm not sure why you want to define constants for individual characters (just use the char, it's a constant!) but the Unicode standard defines a bunch of categories for characters, and you can access those through the Java Character class, which also has some methods for getting a character's type.
Kotlin gives you a CharCategory enum class which contains all these categories, and some functions that make it a little easier - for example you can do this:
println(CharCategory.OTHER_PUNCTUATION.contains(','))
>> true
But for example, '-' is not in the OTHER_PUNCTUATION category, aka category Po. That comes under DASH_PUNCTUATION, Pd. If you notice, all the punctuation category codes start with P, so you could do this kind of thing:
val punctuationCategories
= CharCategory.values().filter { it.code.first() == 'P' }
val Char.isPunctuation: Boolean get() = punctuationCategories.any { it.contains(this) }
println('-'.isPunctuation)
>> true
That's just a basic overview and pointing out this stuff is baked into the Unicode standard - I don't really know a lot about it (I can't see a more convenient way to do this but I could be wrong) and I'm not sure if it's helpful, but there it is!
Kotlin does have an object full of constants for "Unicode symbols used in proper Typography" for some reason though! Also a couple with typos in the name so they had to deprecate them, now that's what I call typography
edit: I should point out that Unicode aims to represent every writing system that ever existed, so its scope of what counts as "punctuation" might be a bit broader than what you're looking for! It depends if you're just trying to check a character, or if you want to create a collection of punctuation characters. If you just want to limit things to a particular Charset, like US_ASCII or whatever, I'm not sure how you can get access to all the characters that covers
We are building an Android application where we use Timber for Log-output. We have defined our own .e, .d, .v etc functions and use if (BuildConfig.DEBUG) to see if we should output the log. This takes care of the issue that we don't want to output Debug-logs in our releases but all the string literals used in our functions calls are still present in the compiled source code. We furthermore use ProGuard for obfuscation. To exemplify, in a class we can have:
somObj.normalFunction(variable)
Log.d("This secret class achieved its secret mission!");
In our release, this will not be seen in the app logs but if you reverse-engineer the APK you will see something like:
q.b(m)
z.a("This secret class achieved its secret mission!");
which can give a hint to the hackers about what class they are looking at.
So what we're looking for is to either be able to completely REMOVE all the Log function calls at compile time (using some pre-processing, annotation or something, but hopefully without having to add something before EVERY function call) OR to obfuscate all the String literal parameters to those function calls. So, two ideal solutions would be if the source, just before compilation, instead looks like:
q.b(m);
or
q.b(m);
z.a("jgasoisamgp23mmwaföfm,ak,ä")
Just by thinking I can see two bad ways to achieve this. Either we surround ALL calls to Log.d with if(BuildConfig.DEBUG) which will make the compiler remove them before compilation. But this is very tideous. OR, we make sure that every time you want to add a log-printout you need to do
Log.d(LogClass.getLog(1234))
and you then define ALL those logs inside LogClass and then remove them with if(BuildConfig.DEBUG) and return null in getLog if that's the case. But that makes it more tideous every time you want to add a log.
So finally, is there any GOOD solution to this?
DISCLAIMER: I work for PreEmptive, the company that makes PreEmptive Protection - DashO.
DashO is capable of removing calls to specific methods (e.g., Log methods). While this doesn't remove the instructions to load the string literal, just the call itself, DashO also offers String Encryption, which would offer some protection to those string literals.
As an example, I ran this class through DashO:
public class App {
public static void main(String[] args) {
Log.d("Secret message here");
}
}
After removing calls to Log.d with String Encryption on, the decompiled output looks like this:
public class App
{
public static void main(String[] paramArrayOfString)
{
a.replace("Bwpfpb7u|ih}z{?($0&", -12 - -61);
}
}
DashO offers other protections (e.g., Control Flow Obfuscation) that tend to break decompilers; I've turned those off for this demonstration.
What I would do is one or some of the following:
Use Timber (so you don't need to bother removing things or adding if statements). You simply do this once in your Application#onCreate(); if you are in DEBUG, then you plant a DebugTree that prints to the console. Else, you plant an "empty tree" that does nothing.
Simulate Timber but create your own "YourLogger" class and do the same (if you don't want to include a "third-party" library even though it's just one class). So you'd have YourLogger.v("tag", "string") and inside you'd do: if (debug) { Log.v(tag, string); } and so on and so forth for all other log types.
Use Proguard to strip the logging, and what not.
1 and 2 imply you go through your app and replace all Log. lines with either Timber. or YourLogger.
Option 3 wouldn't need that, since the code would be removed during obfuscation and the calls would do nothing, but this is mode complicated (and I haven't done it in years, don't even remember how it's done, probably easy to look it up).
I'd go for 1.
Update
Since apparently I don't know how to read, I think that in order to achieve this, your only bet is to have some sort of lookup mechanism for the actual text you want to emit/hide.
Strings.xml is the easiest, since it's included with Android and you can even localize the error messages (if that were needed, of course). Yes, there's a lookup time penalty, but I'd say unless you're iterating over thousands of items and logging different strings every time or something, the penalty wont' be noticeable (I don't have data for this, you'd have to benchmark).
Alternatively, instead of relying on resources, you could just use a file, read it, and load the strings in memory... a trade off; do you use more memory at the cost of simplicity and time to code the solution, or do you use the built-in mechanism and pay the CPU time?
My app uses a lot of static text and I'm trying to find an optimal way to persist and display that text. For now, I don't need to focus on localizing the text so, all the text goes into the strings.xml and that presents a lot of formatting nightmares.
Of course, it is not 100% static content, I sometimes have dynamic values in there which in my case can stay within strings.xml so, what is the right way for persisting this static text?
Static text content is exactly what you want to use strings.xml for, and you automatically get the added bonus of easier localization as you can have different strings.xml for the different languages. No code changes required, just different XML files.
Dynamic content is going to be content which changes based on user input. You can still use strings.xml to store the static portion (if any) of that dynamic content. Like the "format" string you may pass to String.format() or something similar.
Use the resources support for this, it is exactly what it was intended to do (and do it efficiently.)
Your comment is contradictory; you say:
For now, I don't need to focus on localizing the text so, all the text goes into the strings.xml
if you don't need Localizing, then why are you using strings.xml?
Of course, the answer is because regardless of localizing, strings.xml is the perfect place for this.
I don't know what kind of nightmares you have with it, but it's not different from any other string:
E.g. of a strings.xml:
<string name="refresh">Refresh</string>
<string name="order_placed" formatted="false">Order Placed: %s</string>
You can later use the same formatter for them:
getString(R.string.order_placed, "3pm")
will output:
Order Placed: 3pm
If you need new lines…
<string name="error">Something bad happened.\nPlease try again.</string>
will output:
Something bad happened.
Please try again.
And so forth.
Additionally, if you have trouble naming your resources, I've been following more or less this idea and despite the shortcomings described at the bottom, they haven't been a big deal with Android Studio fancy refactoring tools.
You could create a class called StaticBuffer or something with a static String array as a data member.
class StaticBuffer
{
static String array[];
}
Then you could initialize it in your onCreate() or any other function and use it.As it is static it's values will reflect the changes that you make everywhere.
Eg :
//Initialization
StaticBuffer.array=new String[10];
//Usage
StaticBuffer.array[0]="Item1";
PS: I got this idea from a friend of mine. :)
What is the best way to test if string is empty?
I know it is possible to use if/else condition but is there possibility to use while loop?
I used both variants but in my case (see on picture) the while loop do not work and still get the empty string error. And is there some more elegant way to evaluate more fields in one while loop?
What is the best way to test if string is empty?
use the is empty block
but is there possibility to use while loop?
to use a while loop to do some data validation does not make sense, because as you already found out, a while loop will block your device and will result in a runtime error. See also The model of event processing in App Inventor by Lyn
is there some more elegant way to evaluate more fields in one while
loop?
instead of using a while loop, use an if - then - elseif - elseif - ... - else statement, see also the documentation
I am trying to extract the X and Y component using a regular expression from the following data:
{"SearchResults":[{"PageCount":"0"},
{"SEARCHVAL":"530106","CATEGORY":"Building",
"X":"103.8907","Y":"1.3537"}]}
This is the pattern I tried to no avail:
Pattern p1 = Pattern.compile("\\\"X:\\\"([0-9.]*)\\\",\\\"Y\\\":\"([0-9.]*)\\\"");
Matcher m1 = p1.match(result);
if( m1.matches() ){
print("match found");
}
I have also tried the following without any luck:
Pattern.compile("\"X:\"([0-9.]*)\",\"Y\":\"([0-9.]*)\"");
This should be easy, but yet I have been stuck here for the past 2 hours.
If you want regex to parse it, then you can use:
"X":"(\d+(?:\.\d+)?)","Y":"(\d+(?:\.\d+)?)"
Regex Demo
You are missing a quote(") after X in your regex. Though I recommend not to use your regex because it will also match 1.1.2.3
In JAVA:
\"X\":\"(\\d+(?:\\.\\d+)?)\",\"Y\":\"(\\d+(?:\\.\\d+)?)\"
This RegEx will work:
"X":"([0-9.]*)","Y":"([0-9.]*)"
The 1st Capture Group contains the X value, and the 2nd Capture Group contains the Y value
Live Demo on Regex101
Which means your Pattern.compile should be:
Pattern.compile("\"X\":\"([0-9.]*)\",\"Y\":\"([0-9.]*)\"");
Note that you may need to add .* at the start of the RegEx for it to work.
for others that are stuck with the same problem, the reason why .* is needed at the front/end is because i used the wrong method call.
according to http://developer.android.com/reference/java/util/regex/Matcher.html#matches()
public boolean matches ()
Added in API level 1 Tries to match the Pattern against the entire
region (or the entire input, if no region has been set).
It needs to match the entire region.
to do any match, i would need to use find() instead.
public boolean find ()
Added in API level 1 Moves to the next occurrence of the pattern in
the input. If a previous match was successful, the method continues
the search from the first character following that match in the input.
Otherwise it searches either from the region start (if one has been
set), or from position 0.
hope this is useful to others.
String.matches() provides more insights to matches() method http://developer.android.com/reference/java/lang/String.html
public boolean matches (String regularExpression)
This method returns true only if the regular
expression matches the entire input string. A common mistake is to
assume that this method behaves like contains(CharSequence); if you
want to match anywhere within the input string, you need to add .* to
the beginning and end of your regular expression. See matches(String,
CharSequence).