How do I get the position of a substring that was formatted by getString()?

Viewed 144

How can I get the position of the substring that was read in by getString(int resId, Object... formatArgs)?

For example I've got these resources

<string name="fruit">pear</string>
<string name="sentence">I like a <xliff:g id="fruit" example="apple">%s</xliff:g>.</string>

and read them in by

String fruit = getString(R.string.fruit); // = "pear"
String sentence = getString(R.string.sentence, fruit); // = "I like a pear."

I'd like to know where the word "pear" starts for example for underlining it. When the mentioned fruit is at the end of the sentence I can go for

int pos = sentence.length() - fruit.length() - 1;

but this breaks as soon as this changes (for example in a different language). I could search for fruit in sentence but this might break as soon as the same fruit gets mentioned twice for example.

Any ideas about how I can do this reliable? Sadly changing the implementation of resources and data parsing is not an option.

3 Answers

My recommendation would be to change your string resources to use the <annotation> tag instead of the <xliff:g> tag:

<string name="sentence">I like a <annotation id="fruit" example="apple">%s</annotation>.</string>

If you can do that, then you can retrieve the string resource as a SpannedString using getResources().getText() and then inspect the spans:

SpannedString spanned = (SpannedString) getResources().getText(R.string.sentence);
Annotation[] spans = spanned.getSpans(0, spanned.length(), Annotation.class);
int startPosition = spanned.getSpanStart(spans[0]);

Then you can format it for display:

String fruit = getString(R.string.fruit);
String sentence = String.format(spanned.toString(), fruit);

If you can't change your resources at all, you can do something similar by using getString() without extra parameters to retrieve the string with its format arguments (%s) and then use indexOf() on that:

String text = getResources().getString(R.string.sentence);
int startPosition = text.indexOf("%s");

And then format it for display the same way:

String fruit = getString(R.string.fruit);
String sentence = String.format(text, fruit);

This is worse for many reasons (the string could theoretically include "%s" as a non-format-argument substring, you need to know the exact specification of the format arguments ahead of time, etc). But it might be the best you can do if you can't change anything else.

You can split Your string like this:

 String[] parts = sentence.split(" " + fruit + " ");
 String part1 = parts[0];
 int pos = part1.length() + 1;

part1 is a string that contains everything before " pear ", so its length is the position where word "pear" starts minus 1 (we need to use " " before and after the word to ensure that we will not find it as part of unrelated word in sentence).

Use the indexOf method

int pos = sentence.indexOf(fruit);
Related