Highlighting certain part of InlineSpans in flutter

137 views Asked by At

I m developing a e book application with data that consists some custom tags like < t >, < nm >, < ar >, < bs >,< mean > and these tags wrapped with < t >

My text like below;

< t > < title >İkinci Lem’a< /title >< t > < bs > ﷽ < /bs >< t > < ar >اِذْ نَادٰي رَبَّهُٓ اَنّ۪ى مَسَّنِىَ الضُّرُّ وَاَنْتَ اَرْحَمُ الرَّاحِم۪ينَ< /ar >< t > < t ><nm>1</nm><t>\nSabır kahramanı Hazret-i Eyyub Aleyhisselâmın şu < t >< mean >münâcât< /mean >< t >ı, hem < t >< mean >mücerreb< /mean >< t >, hem tesirlidir. <t><nm>2</nm><t>Fakat ayetten <t><mean>iktibas</mean><t> <mean>suret</mean><t>inde, bizler, <t><mean>münâcât</mean><t >ımızda\t\t\t\t < t >< ar >رَبّ۪ى اِنّ۪ى مَسَّنِىَ الضُّرُّ وَاَنْتَ اَرْحَمُ الرَّاحِم۪ينَ< / ar>

I split text with tag and according to corresponding tag I create Text or widget spans according to tag. then I want to make highlight some text without concerning what kind of span or textStyle data has. I tried many methods but cant success.

I tried to split reference words that will be highlighted no success. I splitted words and checked if reference string consists. that gives partial solution but it also highlihgts different parts of text which is not intended to highlihgt.

my reference string is :

String tt = "Hazret-i Eyyub Aleyhisselâmın meşhur kıssasının hülâsası şudur ki: \nPek çok yara bere içinde epey müddet kaldığı halde, o hastalığın azîm mükâfatını düşünerek, kemal-i sabırla tahammül edip kalmış.";

when I run it looks like this :

image

I just want only string equals to reference string has backround color.

this function where I split string and create spanlist

List<InlineSpan> getText(String t,) {
v = t.removeTags();

    List<InlineSpan> spans = [];

    List<String> words = t.split("<t>");

    for (var word in words) {
      if (isImage(word)) {
        spans.add(imageSpan(word,));
      } else if (isTitle(word).$1) {
        spans.add(titleSpan(word));
      } else if (hasMeaning(word)) {
        spans.add(meaningsSpan(word));
      } else if (isSn(word)) {
        spans.add(snSpan(word));
      } else if (isBesmele(word)) {
        spans.add(besmeleSpan(word));
      } else if (isYildiz(word)) {
        spans.add(yildizSpan(word));
      } else if (isNumber(word)) {
        spans.add(ayetNumberSpan(word));
      } else if (isHasiye(word)) {
        spans.add(hasiyeSpan(word));
      } else if (isArabic(word)) {
        spans.add(arapcaSpan(word));
      } else {
  
        spans.add(textSpan(word, word, null, null));
      }
    }

    return spans;
  }

this is the textSpan that returns custom styles according to tags words consist

TextSpan textSpan(String text, String word, double? height, Function(TapUpDetails)? onTapUp) {

    final list = text.split(" ");
    final length = list.length;
    return   TextSpan(
      children: list.mapIndexed((index, e){
var s = "";

if(index ==0){
 s = e;
}else if(index>0&& index==length){
  s = "${text.split(" ")[index - 1]??""} $e ";
}else if(index>0&& index<length-1){
  s = "${text.split(" ")[index - 1]??""} $e ${text.split(" ")[index +1]??""}";
}else if(index<length-1){
  s = "${text.split(" ")[index - 1]??""} $e ${text.split(" ")[index +1]??""}";
}

        return TextSpan(
         text: e + " ",
        style: TextStyle(
            color: getColor(word),
            fontSize: getFontSize(word),
            fontFamily: getFont(word),
            fontWeight: getFontWeight(word),
            fontStyle: getFontStyle(word),
            backgroundColor:  commentColor(s ),
            height: height),
            recognizer: TapGestureRecognizer()..onTapUp = onTapUp);
     
      } ).toList()
      
 
       );

  }

I tried to split span text and tried to looked previous word or next word of every word and tried to find exact match in reference string. but no success

and this is the function I try to add highlight color to text style

Color? commentColor(String s){

    RegExp exp =  RegExp( "\\b$s\\b", caseSensitive: false, ); 
    bool contains = exp.hasMatch(tt);
  
    if(contains){
    return Colors.cyan;
  }

  return null;
} 

any ide will be appriciated.

Note: stackoverflow removes tags when I write them without space

2

There are 2 answers

4
pixel On

The issue here is that you're trying to match a multi-line string with a regular expression pattern designed to match a single word. The \\b word boundary anchors in your regular expression are meant to match the boundaries of a single word, not a multi-line string. And must have seen here.

In the commentColor function, you're using the RegExp pattern \\b($s)\\b, which tries to match the whole string tt as a single word within the string s. Since tt contains newline characters and spans multiple lines, it doesn't match the word boundary conditions.

So If you want to check if tt appears anywhere in the string s, you can simply use the contains method without regular expressions:

Color? commentColor(String s) {
  bool contains = s.contains(tt);

  if (contains) {
    return Colors.cyan;
  }else{
    return null;
  }
}

and for case-insensitive search just replace the line:

bool contains = s.toLowerCase().contains(tt.toLowerCase());
0
Jannie Theunissen On

How about wrapping all your spans in a parent and then searching on the flattened text:

final wrapper = TextSpan(children: spans);
final haystack = wrapper.toPlainText();