<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Text Processing &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/text-processing/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Thu, 02 Apr 2026 16:09:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Build a Simple Find in Files Function</title>
		<link>https://blog.xojo.com/2026/04/02/build-a-simple-find-in-files-function/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Thu, 02 Apr 2026 16:15:00 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Files]]></category>
		<category><![CDATA[Search]]></category>
		<category><![CDATA[Text Files]]></category>
		<category><![CDATA[Text Processing]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15972</guid>

					<description><![CDATA[Sooner or later most apps need some version of the ability to find text in those files, whether you&#8217;re scanning log files, config files, exported&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Sooner or later most apps need some version of the ability to find text in those files, whether you&#8217;re scanning log files, config files, exported data, or source code.</p>



<p>In this post, we&#8217;ll build a simple Find in Files utility in Xojo that:</p>



<ul class="wp-block-list">
<li>searches the files in a folder</li>



<li>reads each file line by line</li>



<li>performs a plain-text, case-insensitive match</li>



<li>returns the file path, line number, and matching line</li>
</ul>



<p>The goal is simple: build something useful while leaving the door open for the fancier stuff.</p>



<h2 class="wp-block-heading" id="what-this-find-in-files-function-will-do">What this Find in Files function will do</h2>



<p>Let&#8217;s keep the scope clear:</p>



<ul class="wp-block-list">
<li>search one folder</li>



<li>search plain text only</li>



<li>skip subfolders for now</li>



<li>return the matching file path, line number, and line contents</li>
</ul>



<h2 class="wp-block-heading" id="step-1-put-the-result-class-in-the-module">Step 1: A class in a module and some properties</h2>



<p>Before touching the file system, let&#8217;s define what a match looks like.</p>



<p>You could return raw strings, but that gets messy fast. A small class keeps the code readable and gives us an obvious place to extend later. In this version, I like keeping that class inside the same module as the search function. It keeps the entire utility self-contained instead of spraying helper types all over the project.</p>



<p>So, we start by adding a module&nbsp;<code>SearchUtils</code>&nbsp;and inside the module we will add a class&nbsp;<code>SearchHit</code>.</p>



<pre class="wp-block-code"><code>Module SearchUtils

  Class SearchHit

    Public Property FilePath As String
    Public Property LineNumber As Integer
    Public Property LineText As String

    Public Sub Constructor(filePath As String, lineNumber As Integer, lineText As String)
      Self.FilePath = filePath
      Self.LineNumber = lineNumber
      Self.LineText = lineText
    End Sub

  End Class

End Module</code></pre>



<p>Each result stores three things:</p>



<ol class="wp-block-list">
<li>the file path</li>



<li>the line number</li>



<li>the matching line</li>
</ol>



<h2 class="wp-block-heading" id="step-2-walk-through-the-folder">Step 2: Walk through the folder</h2>



<p><code>FolderItem.Children</code> lets us loop through a folder with a <code>For Each</code> loop, which keeps the code clear.</p>



<p>We&#8217;ll also reject bad input early:</p>



<ul class="wp-block-list">
<li>the folder is&nbsp;<code>Nil</code></li>



<li>the folder does not exist</li>



<li>the item passed is not actually a folder</li>



<li>the search term is empty</li>
</ul>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="409" src="https://blog.xojo.com/wp-content/uploads/2026/03/find_in_files_xojo_function_diagram2-1024x409.png" alt="" class="wp-image-16027" srcset="https://blog.xojo.com/wp-content/uploads/2026/03/find_in_files_xojo_function_diagram2-1024x409.png 1024w, https://blog.xojo.com/wp-content/uploads/2026/03/find_in_files_xojo_function_diagram2-300x120.png 300w, https://blog.xojo.com/wp-content/uploads/2026/03/find_in_files_xojo_function_diagram2-768x307.png 768w, https://blog.xojo.com/wp-content/uploads/2026/03/find_in_files_xojo_function_diagram2.png 1536w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>This process is simple, fast and effective.</p>



<h2 class="wp-block-heading" id="step-3-read-files-line-by-line">Step 3: Read files line by line</h2>



<p>For text files,&nbsp;<code>TextInputStream.Open</code>&nbsp;is the right tool. From there, we can call&nbsp;<code>ReadLine</code>&nbsp;until&nbsp;<code>EndOfFile</code>&nbsp;becomes&nbsp;<code>True</code>.</p>



<p>I prefer this over&nbsp;<code>ReadAll</code>&nbsp;for a utility like this.&nbsp;<code>ReadAll</code>&nbsp;is fine when the file is small and you know what you&#8217;re doing, but line-by-line reading is a better default here. It keeps memory use in check and gives us line numbers for free.</p>



<p>For the sample code, I&#8217;m explicitly using UTF-8:</p>



<pre class="wp-block-code"><code>input.Encoding = Encodings.UTF8</code></pre>



<p>That keeps the sample predictable. It does&nbsp;<strong>not</strong>&nbsp;mean this code can gracefully decode every text file you throw at it. Files with unknown encodings or binary-ish content are a separate problem, and they deserve their own solution.</p>



<h2 class="wp-block-heading" id="step-4-match-the-text">Step 4: Match the text</h2>



<p>For a plain-text search,&nbsp;<code>String.Contains</code>&nbsp;does exactly what we need:</p>



<pre class="wp-block-code"><code>line.Contains(searchTerm, ComparisonOptions.CaseInsensitive)</code></pre>



<p>It handles the case-insensitivity without the overhead, or the headache, of regex.</p>



<h2 class="wp-block-heading" id="step-5-the-full-module">Step 5: The full module and class and function</h2>



<pre class="wp-block-code"><code>Module SearchUtils

  Public Class SearchHit
    Public Property FilePath As String
    Public Property LineNumber As Integer
    Public Property LineText As String

    Public Sub Constructor(filePath As String, lineNumber As Integer, lineText As String)
      Self.FilePath = filePath
      Self.LineNumber = lineNumber
      Self.LineText = lineText
    End Sub
  End Class

  Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String) As SearchHit()
    Var hits() As SearchHit

    If targetFolder Is Nil Then
      Return hits
    End If

    If Not targetFolder.Exists Or Not targetFolder.IsFolder Then
      Return hits
    End If

    If searchTerm.IsEmpty Then
      Return hits
    End If

    For Each item As FolderItem In targetFolder.Children
      If item Is Nil Then Continue
      If item.IsFolder Then Continue
      If Not item.Exists Then Continue
      If Not item.IsReadable Then Continue

      Try
        Var input As TextInputStream = TextInputStream.Open(item)
        input.Encoding = Encodings.UTF8

        Var lineNumber As Integer = 0

        While Not input.EndOfFile
          Var line As String = input.ReadLine
          lineNumber = lineNumber + 1

          If line.Contains(searchTerm, ComparisonOptions.CaseInsensitive) Then
            hits.Add(New SearchHit(item.NativePath, lineNumber, line))
          End If
        Wend

        input.Close

      Catch error As IOException
        ' Skip files that cannot be read as text.
        Continue
      End Try
    Next

    Return hits
  End Function

End Module</code></pre>



<h2 class="wp-block-heading" id="how-it-works">How it works</h2>



<p>Let&#8217;s break down the important parts.</p>



<h3 class="wp-block-heading" id="input-validation">Input validation</h3>



<p>This block prevents pointless work and avoids avoidable runtime problems:</p>



<pre class="wp-block-code"><code>If targetFolder Is Nil Then
  Return hits
End If

If Not targetFolder.Exists Or Not targetFolder.IsFolder Then
  Return hits
End If

If searchTerm.IsEmpty Then
  Return hits
End If</code></pre>



<p>Rule of thumb: reject bad input early.</p>



<h3 class="wp-block-heading" id="folder-iteration">Folder iteration</h3>



<p>This is the core loop:</p>



<pre class="wp-block-code"><code>For Each item As FolderItem In targetFolder.Children</code></pre>



<p>We&#8217;re only scanning the folder&#8217;s immediate contents. If an item is another folder, we skip it.</p>



<pre class="wp-block-code"><code>If item.IsFolder Then Continue</code></pre>



<h3 class="wp-block-heading" id="safe-text-reading">Safe text reading</h3>



<p>Each file is opened with&nbsp;<code>TextInputStream.Open</code>&nbsp;inside a&nbsp;<code>Try...Catch</code>&nbsp;block:</p>



<pre class="wp-block-code"><code>Try
  Var input As TextInputStream = TextInputStream.Open(item)
  input.Encoding = Encodings.UTF8
  ...
Catch error As IOException
  Continue
End Try</code></pre>



<p>That way, one unreadable file does not take down the whole search. It gets skipped and the rest of the folder still gets processed.</p>



<h3 class="wp-block-heading" id="line-by-line-matching">Line-by-line matching</h3>



<p>This is where the actual work happens:</p>



<pre class="wp-block-code"><code>While Not input.EndOfFile
  Var line As String = input.ReadLine
  lineNumber = lineNumber + 1

  If line.Contains(searchTerm, ComparisonOptions.CaseInsensitive) Then
    hits.Add(New SearchHit(item.NativePath, lineNumber, line))
  End If
Wend</code></pre>



<p>Because we&#8217;re reading one line at a time, attaching the correct line number is trivial.</p>



<h3 class="wp-block-heading" id="why-keep-searchhit-inside-the-module">Why keep&nbsp;<code>SearchHit</code>&nbsp;inside the module?</h3>



<p>Because it belongs to this utility. The search function and its result type are part of the same little unit of behavior, so keeping them together makes the project easier to scan and easier to transform it to a&nbsp;<a href="https://documentation.xojo.com/topics/code_management/sharing_code_among_multiple_projects.html" target="_blank" rel="noreferrer noopener">Library</a>.</p>



<p>It also means code outside the module uses the namespaced type:</p>



<pre class="wp-block-code"><code>Var results() As SearchUtils.SearchHit = SearchUtils.FindInFiles(folder, "xojo")</code></pre>



<h2 class="wp-block-heading" id="using-the-function">Using the function</h2>



<p>Here&#8217;s a simple example that lets the user choose a folder and then writes the results to the debug log:</p>



<pre class="wp-block-code"><code>Var folder As FolderItem = FolderItem.ShowSelectFolderDialog
If folder Is Nil Then Return

Var results() As SearchUtils.SearchHit = SearchUtils.FindInFiles(folder, "error")

For Each hit As SearchUtils.SearchHit In results
  System.DebugLog(hit.FilePath + " | line " + hit.LineNumber.ToString + " | " + hit.LineText)
Next</code></pre>



<p>If you want to display the results in a&nbsp;<code>DesktopListBox</code>, that works nicely too:</p>



<pre class="wp-block-code"><code>Var folder As FolderItem = FolderItem.ShowSelectFolderDialog
If folder Is Nil Then Return

Var results() As SearchUtils.SearchHit = FindInFiles(folder, "error")

ListBox1.RemoveAllRows
ListBox1.ColumnCount = 3

For Each hit As SearchUtils.SearchHit In results
  ListBox1.AddRow(hit.FilePath)
  ListBox1.CellTextAt(ListBox1.LastAddedRowIndex, 1) = hit.LineNumber.ToString
  ListBox1.CellTextAt(ListBox1.LastAddedRowIndex, 2) = hit.LineText
Next</code></pre>



<p>A few sample results might look like this:</p>



<pre class="wp-block-code"><code>C:\Logs\app.log | line 18 | Error connecting to database
C:\Logs\app.log | line 42 | Error writing audit record
C:\Configs\service.txt | line 7 | Last error message: timeout</code></pre>



<h2 class="wp-block-heading" id="practical-limitations-of-this-version">Practical limitations of this version</h2>



<p>This utility is useful, but limited.</p>



<h3 class="wp-block-heading" id="it-assumes-utf-8">It assumes UTF-8</h3>



<p>That is fine for plenty of modern text files, but not all of them. If you&#8217;re dealing with mixed encodings, you&#8217;ll need a smarter approach that detects the file encoding.</p>



<h3 class="wp-block-heading" id="it-doesnt-recurse-into-subfolders">It doesn&#8217;t recurse into subfolders</h3>



<p>That is deliberate. Recursive search is useful, but it adds another layer of behavior and another place to make the code harder to read.</p>



<h2 class="wp-block-heading" id="final-thoughts">Final thoughts</h2>



<p>A basic Find in Files function is one of those utilities that looks small but pays off quickly. This is a base-layer utility. Once you have this working, adding recursion or regex is a much smaller lift.</p>



<p>Let&#8217;s discuss in the&nbsp;<a href="https://forum.xojo.com/">forums</a>.</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RegEx Examples: 10 Practical Patterns You Can Copy and Paste</title>
		<link>https://blog.xojo.com/2025/09/18/regex-examples-10-practical-patterns-you-can-copy-and-paste/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Thu, 18 Sep 2025 11:00:00 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Code Snippets]]></category>
		<category><![CDATA[Data Extraction]]></category>
		<category><![CDATA[RegEx]]></category>
		<category><![CDATA[Text Processing]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=15351</guid>

					<description><![CDATA[Looking for RegEx examples you can drop straight into your project? This practical cheat sheet focuses on the most searched tasks, such as find/replace, extracting&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Looking for RegEx examples you can drop straight into your project? This practical cheat sheet focuses on the most searched tasks, such as find/replace, extracting values, lookahead/lookbehind, and non-greedy matches, using Xojo’s RegEx class with concise, ready-to-run snippets. Copy, paste, ship.</p>



<h2 class="wp-block-heading" id="setup-3-lines-you’ll-reuse">Setup (3 lines you’ll reuse)</h2>



<pre class="wp-block-code"><code>Var re As New RegEx
Var opt As New RegExOptions
re.Options = opt</code></pre>



<h2 class="wp-block-heading" id="replace-all-occurrences-word-boundary">1) Replace all occurrences (word boundary)</h2>



<p>Goal: a → the (whole word)</p>



<pre class="wp-block-code"><code>Var re As New RegEx
Var opt As New RegExOptions
opt.ReplaceAllMatches = True
re.Options = opt

re.SearchPattern = "\ba\b"
re.ReplacementPattern = "the"
MessageBox(re.Replace("a bus on a street in a town"))
' the bus on the street in the town</code></pre>



<h2 class="wp-block-heading" id="strip-html-tags">2) Strip HTML tags</h2>



<pre class="wp-block-code"><code>Var re As New RegEx
Var opt As New RegExOptions
opt.ReplaceAllMatches = True
re.Options = opt

re.SearchPattern = "&lt;&#91;^&lt;>]+>"
re.ReplacementPattern = ""
MessageBox(re.Replace("&lt;p>Hello &lt;b>world&lt;/b>.&lt;/p>"))
' Hello world.</code></pre>



<h2 class="wp-block-heading" id="extract-the-first-number-capture-groups">3) Extract the first number (capture groups)</h2>



<pre class="wp-block-code"><code>re.SearchPattern = "(\d+)"
Var m As RegExMatch = re.Search("Order #12345 shipped")
If m &lt;> Nil Then MessageBox(m.SubExpressionString(1)) ' 12345</code></pre>



<h2 class="wp-block-heading" id="reformat-dates-with-1-2-3">4) Reformat dates with $1, $2, $3</h2>



<p>Goal: YYYY-MM-DD → DD/MM/YYYY</p>



<pre class="wp-block-code"><code>Var re As New RegEx
Var opt As New RegExOptions
opt.ReplaceAllMatches = True
re.Options = opt

re.SearchPattern = "(\d{4})-(\d{2})-(\d{2})"
re.ReplacementPattern = "$3/$2/$1"
MessageBox(re.Replace("Due: 2025-09-09 and 2025-12-31"))
' Due: 09/09/2025 and 31/12/2025</code></pre>



<h2 class="wp-block-heading" id="find-all-words-simple-iterator">5) Find all words (simple iterator)</h2>



<pre class="wp-block-code"><code>re.SearchPattern = "\w+"
Var match As RegExMatch = re.Search("one two three")
While match &lt;> Nil
  System.DebugLog(match.SubExpressionString(0))
  match = re.Search ' continues from last position
Wend</code></pre>



<h2 class="wp-block-heading" id="replace-only-the-second-occurrence">6) Replace only the second occurrence</h2>



<pre class="wp-block-code"><code>Var s As String = "a bus drove on a street in a town"
re.SearchPattern = "\ba\b"
re.ReplacementPattern = "the"

Var first As RegExMatch = re.Search(s) ' find first
If first &lt;> Nil Then
  s = re.Replace ' replaces the next match only
End If

MessageBox(s)
' a bus drove on the street in a town</code></pre>



<h2 class="wp-block-heading" id="lookarounds">7) Lookarounds</h2>



<p>Match “foo” not followed by “bar”</p>



<pre class="wp-block-code"><code>re.SearchPattern = "foo(?!bar)"</code></pre>



<h3 class="wp-block-heading" id="negative-lookahead-match-only-http-not-https-urls">7.1 Negative lookahead: match only http (not https) URLs</h3>



<pre class="wp-block-code"><code>Var re As New RegEx
re.SearchPattern = "http(?!s)://\S+" ' http:// not followed by s
Var txt As String = "http://a.com and https://b.com"
Var m As RegExMatch = re.Search(txt)
While m &lt;> Nil
  System.DebugLog(m.SubExpressionString(0)) ' http://a.com
  m = re.Search
Wend</code></pre>



<h3 class="wp-block-heading" id="positive-lookbehind--optional-decimals-amounts-right-after-">7.2 Positive lookbehind + optional decimals: amounts right after $</h3>



<pre class="wp-block-code"><code>Var re As New RegEx
re.SearchPattern = "(?&lt;=\$)\d+(?:\.\d{2})?" ' $123 or $123.45 → capture just the number
Var txt As String = "Total: $19.99, Tax: $2"
Var m As RegExMatch = re.Search(txt)
While m &lt;> Nil
  System.DebugLog(m.SubExpressionString(0)) ' 19.99, 2
  m = re.Search
Wend</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Tip:</p>



<ul class="wp-block-list">
<li>Fixed‑width only for look‑behind: avoid quantifiers like +, * inside (?&lt;=…)/(?&lt;!…).</li>



<li>Use lookarounds when you need context to the left/right but don’t want it included in the match or replacement.</li>
</ul>
</blockquote>



<h2 class="wp-block-heading" id="smallest-span-between-tags-non‑greedy">8) Smallest span between tags (non‑greedy)</h2>



<pre class="wp-block-code"><code>re.SearchPattern = "&lt;b>.+?&lt;/b>" ' or: opt.Greedy = False</code></pre>



<h2 class="wp-block-heading" id="extract-emails-simple-demo">9) Extract emails (simple demo)</h2>



<pre class="wp-block-code"><code>re.SearchPattern = "&#91;A-Za-z0-9._%+-]+@&#91;A-Za-z0-9.-]+\.&#91;A-Za-z]{2,}"
Var em As RegExMatch = re.Search("Contact: me@example.com")
If em &lt;> Nil Then MessageBox(em.SubExpressionString(0)) ' me@example.com</code></pre>



<h2 class="wp-block-heading" id="start-at-character-position-n-utf‑8-safe">10) Start at character position N (UTF‑8 safe)</h2>



<pre class="wp-block-code"><code>Var t As String = "ąβç sample"
Var charPos As Integer = 5 ' 1-based character index
re.SearchPattern = "\w+"
re.SearchStartPosition = t.Left(charPos - 1).Bytes ' convert char index → byte offset
Var mm As RegExMatch = re.Search(t)
If mm &lt;> Nil Then System.DebugLog(mm.SubExpressionString(0))</code></pre>



<h2 class="wp-block-heading" id="quick-replacement-references">Quick replacement references</h2>



<ul class="wp-block-list">
<li><strong>$&amp;</strong>&nbsp;= entire match (This reference represents the&nbsp;<em>exact</em>&nbsp;piece of text that your regular expression found. It’s incredibly useful if you want to add something before or after the matched text without changing the match itself.)</li>



<li><strong>$1…$50</strong>&nbsp;= captured groups (Regular expressions allow you to define specific “groups” within your match by enclosing parts of your pattern in parentheses&nbsp;<code>()</code>. Each set of parentheses creates a captured group.)</li>



<li><strong>$`</strong>&nbsp;= text before the match (This special reference represents&nbsp;<em>all</em>&nbsp;the text in your original string that appears&nbsp;<em>before</em>&nbsp;the part your regular expression matched. It’s handy if you want to keep the beginning of the string intact while making a change in the middle.)</li>



<li><strong>$’</strong>&nbsp;= text after the match (This refers to&nbsp;<em>all</em>&nbsp;the text in your original string that comes&nbsp;<em>after</em>&nbsp;the current match. It’s useful for preserving the end of the string.)</li>
</ul>



<h2 class="wp-block-heading" id="options-you’ll-use-most">Options you’ll use most</h2>



<pre class="wp-block-code"><code>opt.ReplaceAllMatches = True  ' global replace
opt.CaseSensitive = True      ' default is False
opt.DotMatchAll = True        ' make . match newlines
opt.Greedy = False            ' prefer shortest matches
opt.TreatTargetAsOneLine = True ' ^ and $ match whole string</code></pre>



<h2 class="wp-block-heading" id="common-gotchas">Common gotchas</h2>



<ul class="wp-block-list">
<li>Greediness: “.+” can overmatch; use .+? or set Greedy = False.</li>



<li>Case sensitivity: default searches are case‑insensitive; enable CaseSensitive when exact case matters.</li>



<li>UTF‑8: SearchStartPosition is byte‑based; convert character index to bytes (see example ↑).</li>



<li>Lookbehind must be fixed‑width.</li>



<li>Iteration: After the first Search(targetString), call re.Search with no args to continue.</li>
</ul>



<h2 class="wp-block-heading" id="wrap‑up">Wrap‑up</h2>



<p>Got a tricky pattern, validation, parsing, or a lookaround edge case you want covered? Drop a comment in the forums with your use.</p>



<p>Happy matching!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
