Android Code Snippet CSBuilder marking based on regex pattern

Similar threads

B4A Tutorial CharSequence / CSBuilder Tutorial
B4A Code Snippet CSBuilder with leading margin
B4A Code Snippet Custom Toast Message
B4A Question CsBuilder / Activity.Title
B4A Code Snippet Save and load CSBuilders

Erel

Administrator
Staff member
Licensed User
This sub searches for matches and uses CSBuilder to mark the matches.



B4X:
Sub MarkPattern(Input As String, Pattern As String, GroupNumber As Int) As CSBuilder
   Dim cs As CSBuilder
   cs.Initialize
   Dim lastMatchEnd As Int = 0
   Dim m As Matcher = Regex.Matcher(Pattern, Input)
   Do While m.Find
     Dim currentStart As Int = m.GetStart(GroupNumber)
     cs.Append(Input.SubString2(lastMatchEnd, currentStart))
     lastMatchEnd = m.GetEnd(GroupNumber)
     'apply styling here
     cs.Bold.Underline
     cs.Color(0xFF03FFFF)
     cs.Clickable("cs", m.Group(GroupNumber))
     cs.Append(m.Group(GroupNumber))
     cs.Pop.Pop.Pop.Pop 'number should match number of stylings set.
   Loop
   If lastMatchEnd < Input.Length Then cs.Append(Input.SubString(lastMatchEnd))
   Return cs
End Sub
Usage example:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("1")
   Dim s As String = $"#Hello, this is a #Nice Day!
#nice test#test
#day"$
   Dim cs As CSBuilder = MarkPattern(s, "\B(#\w+)\b", 1)
   Label1.Text = cs
   cs.EnableClickEvents(Label1)
End Sub

Sub cs_Click (Tag As Object)
   Log($"You have clicked on word: ${Tag}"$)
   Activity.Title = Tag
End Sub
 

Erel

Administrator
Staff member
Licensed User
Another example:



B4X:
Sub Process_Globals
   Private smileyBmp As Bitmap
End Sub

Sub Globals
   Private Label1 As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
       smileyBmp = LoadBitmap(File.DirAssets, "smiley.png")
   End If
   Activity.LoadLayout("1")
   Label1.Text = ReplaceSmilies("hi :) this is text message with smiley sample ;) on how to use csbuilder to replace smiley chars with images :-) and so on")
   
End Sub

Sub ReplaceSmilies(s As String) As CSBuilder
   Dim rb As RegexBuilder
   rb.Initialize
   For Each smiley As String In Array(":)", ";)", ":-)")
       If rb.Pattern <> "" Then rb.AppendOr
       rb.StartNonCapture.AppendEscaped(smiley).EndNonCapture
   Next
   Return MarkPattern(s, rb.Pattern, 0)
End Sub

Sub MarkPattern(Input As String, Pattern As String, GroupNumber As Int) As CSBuilder
   Dim cs As CSBuilder
   cs.Initialize
   Dim lastMatchEnd As Int = 0
   Dim m As Matcher = Regex.Matcher(Pattern, Input)
   Do While m.Find
       Dim currentStart As Int = m.GetStart(GroupNumber)
       cs.Append(Input.SubString2(lastMatchEnd, currentStart))
       lastMatchEnd = m.GetEnd(GroupNumber)
       'apply styling here
       Log(m.Group(GroupNumber))
       cs.Image(smileyBmp, 30dip, 30dip, True)
   Loop
   If lastMatchEnd < Input.Length Then cs.Append(Input.SubString(lastMatchEnd))
   Return cs
End Sub
Notes:
1. The match itself is not appended as we replace it.
2. No need to call Pop after cs.Image
3. RegexBuilder: https://www.b4x.com/android/forum/threads/83495/#content
 

Erel

Administrator
Staff member
Licensed User
Yes. The trick is to create a single pattern with all the capture groups:



B4X:
Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
       smileyBmp = LoadBitmap(File.DirAssets, "smiley.png")
   End If

   Activity.LoadLayout("1")
   Dim s As String = $"#Hello, this is a #Nice Day! :)
#nice :) ;) test#test
#day"$
   Dim rb As RegexBuilder
   'The pattern includes 4 groups (1 - 4). One for the # words and three for the smilies.
   rb.Initialize.StartCapture.Append("\B(?:#\w+)\b").EndCapture
   For Each smiley As String In Array(":)", ";)", ":-)")
       rb.AppendOr
       rb.StartCapture.AppendEscaped(smiley).EndCapture
   Next
   Dim cs As CSBuilder = MarkPattern(s, rb.Pattern)
   Label1.Text = cs
   cs.EnableClickEvents(Label1)
End Sub

Sub cs_Click (Tag As Object)
   Log($"You have clicked on word: ${Tag}"$)
   Activity.Title = Tag
End Sub

Sub MarkPattern(Input As String, Pattern As String) As CSBuilder
   Dim cs As CSBuilder
   cs.Initialize
   Dim lastMatchEnd As Int = 0
   Dim m As Matcher = Regex.Matcher(Pattern, Input)
   Do While m.Find
       For GroupNumber = 1 To m.GroupCount - 1
           If m.Group(GroupNumber) <> Null Then
               Dim currentStart As Int = m.GetStart(GroupNumber)
               cs.Append(Input.SubString2(lastMatchEnd, currentStart))
               lastMatchEnd = m.GetEnd(GroupNumber)
               If GroupNumber = 1 Then
                   cs.Bold.Underline
                   cs.Color(0xFF03FFFF)
                   cs.Clickable("cs", m.Group(GroupNumber))
                   cs.Append(m.Group(GroupNumber))
                   cs.Pop.Pop.Pop.Pop
               Else If GroupNumber >= 2 And GroupNumber <= 4 Then
                   cs.Image(smileyBmp, 30dip, 30dip, True)
               End If
           End If
       Next
   Loop
   If lastMatchEnd < Input.Length Then cs.Append(Input.SubString(lastMatchEnd))
   Return cs
End Sub
 
Top