Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h3>Assumption</h3> <p>A match is defined as a sequence:</p> <ul> <li>Starting from the first <code>"</code> in the input string. Let us call this the 1st <code>"</code> or the opening <code>"</code>.</li> <li>There is no <code>;</code> before the opening <code>"</code></li> <li><code>;</code> is allowed in the sequence, if the last <code>"</code> in the sequence is odd, counting from the 1st <code>"</code>.</li> <li><code>;</code> is not allowed in the sequence, if the last <code>"</code> in the sequence is even, counting from the 1st <code>"</code>.</li> <li>Ends with the furthest <code>"</code> that satisfies the conditions above.</li> </ul> <h3>Solution</h3> <p>Find the <em>first</em> match with this regex (raw form):</p> <pre> ^(?>[^;"]*)"((?>(?>"[^";]*(?="[^"]*$)|"[^";]*"|[^"]*)+))" </pre> <p>In C# string literal:</p> <pre><code>"^(?&gt;[^;\"]*)\"((?&gt;(?&gt;\"[^\";]*(?=\"[^\"]*$)|\"[^\";]*\"|[^\"]*)+))\"" </code></pre> <p>The result will be in the first capturing group.</p> <h3>Explanation</h3> <p>Syntax explanation:</p> <ul> <li><code>(?&gt;pattern)</code> is non-backtracking/possessive sub-expression. It prevents the engine from backtracking. This is a form of optimization.</li> <li><code>(?=pattern)</code> is zero-width positive look-ahead. It checks that the string ahead conforms to the <code>pattern</code> without consuming the text.</li> <li><code>|</code> is alternation. The thing I want to note here is that regex-directed engine will check each rule from left to right, and will not consider other rules if a match is found. That means the order matters in determining the matches.</li> <li>I assume you are familiar with the rest, since they are quite basic.</li> </ul> <p>For the sake of explanation, I will use the raw regex, with the non-backtracking optimization removed:</p> <pre> ^[^;"]*"((?:"[^";]*(?="[^"]*$)|"[^";]*"|[^"]*)+)" </pre> <p>Due to the requirement "first and last quote in a line", there is at most 1 match per line.</p> <p>By doing some analysis on the requirement, we know that the text <em>before</em> the interested portion should not contain <code>;</code> (part of the requirement) or <code>"</code> (otherwise, the quote will not be the first). Therefore, we can write <code>^[^;"]*</code> to anchor the match from the start of the string and match everything up until the first quote <code>"</code>.</p> <p>This is the quoted string part, broken up for ease of explanation:</p> <pre> " ( (?: "[^";]*(?="[^"]*$) | "[^";]*" | [^"]* )+ ) " </pre> <p>Let us focus on these 3 fragments, and I will start explaining from bottom-up:</p> <pre> "[^";]*(?="[^"]*$) "[^";]*" [^"]* </pre> <p>For all cases here, the last quote we encountered is always an odd quote.</p> <ul> <li><code>[^"]*</code>: The last quote is ensured to be odd quote, so we can have anything including <code>;</code>, but except for <code>"</code>.</li> <li><code>"[^";]*"</code>: The last quote is odd quote, and after this is also odd quote. This part deals with the portion after an even quote, where <code>;</code> is disallowed.</li> <li><code>"[^";]*(?="[^"]*$)</code>: This is the tricky part, which deals with the case where the string has an odd number of quotes (>= 3). I made sure that after the even quote, there is no <code>;</code> and followed by the last quote <code>"</code> in the string. <em>"Followed by the last quote <code>"</code> in the string"</em> is achieved with the look-ahead <code>(?="[^"]*$)</code>.</li> </ul> <p>The fragment <code>"[^";]*(?="[^"]*$)</code> must be placed in front of <code>"[^";]*"</code> to avoid backtracking, so that we can apply the non-backtracking optimization.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload