Android Code Snippet [B4X] CSBuilder marking based on regex pattern

CSBuilder is supported by B4A and B4J. There are some differences in the supported properties.
A more powerful cross platform alternative: [B4X] BCTextEngine / BBCodeView - Text engine + BBCode parser + Rich Text View

This sub searches for matches and uses CSBuilder to mark the matches.

1728194704725.png


B4X:
Private Sub MarkPattern(Input As String, Pattern As String, GroupNumber As Int) As CSBuilder
    Dim cs As CSBuilder
    cs.Initialize
    'this section applies to all text
    cs.Color(xui.Color_Black)
    #if B4i
    cs.Font(xui.CreateDefaultBoldFont(14))
    #else if B4A
    cs.Bold
    #end if
    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 match styling here
        cs.Underline
        cs.Color(xui.Color_Blue)
        cs.Append(m.Group(GroupNumber))
        cs.Pop.Pop 'number should match number of stylings set.
    Loop
    If lastMatchEnd < Input.Length Then cs.Append(Input.SubString(lastMatchEnd))
    cs.PopAll
    Return

Usage example:
B4X:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
   
    Dim s As String = $"#Hello, this is a #Nice Day!
#nice test#test
#day"$
    Dim cs As CSBuilder = MarkPattern(s, "\B(#\w+)\b", 1)
    XUIViewsUtils.SetTextOrCSBuilderToLabel(Label1, cs)
End Sub
 

Attachments

  • Project.zip
    180.5 KB · Views: 40
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Another example:

SS-2018-03-18_10.01.06.png


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

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

SS-2018-10-15_09.00.28.png


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