Regular Expressions 101

S⁠ponsors

Community Library

2

JSON Parser for .NET

Created·2026-07-25 18:00
Updated·2026-08-01 19:10
Type·Match
Flavor·.NET 10.0 (C#)
JSON Parser This regular expression is designed to tokenize JSON-like content embedded in INI files. It is not a full JSON validator; instead, it provides a lightweight lexical scanner that identifies structural tokens (objects, arrays, strings, numbers, booleans, null) and ignores comments and whitespace. The token stream is then processed by a hand‑written recursive‑descent parser (with depth‑limit protection) to build a .NET object graph (Dictionary, object], or primitives). Regex Pattern (?//.|/\.?\/)| (?""(?:\\.)"")(?=(?:\s|//.|/\.?\/):)| (?(?true)|(?false)|(?null)|""(?(?:\\.))""|(?-?(?:0|[1-9)(?:\.0-9]+)?(?:[eE?[0-9]+)?))| (?:)| (?\[)| (?,)| (?\])| (?{)| (?})| (?+)| (?[\r\n]+)| (?.+) Named Capture Groups | Group Name | Matches | |------------------|-------------------------------------------------------------------------| | comment | Single‑line //… or multi‑line /…/ comments (skipped). | | key | A JSON property key (double‑quoted string) followed by a colon (lookahead). | | value | A JSON value – one of: true, false, null, a double‑quoted string, or a number (integer, float, or scientific). | | bool | Sub‑group inside value for true/false (for direct parsing). | | null | Sub‑group for null. | | string | Sub‑group for the content inside double‑quotes (without the quotes). | | number | Sub‑group for numeric literals. | | value_sep | A colon : separating key and value. | | array_open | Left bracket [. | | array_sep | Comma , between array elements. | | array_close | Right bracket ]. | | object_open | Left brace {. | | object_close | Right brace }. | | whitespace | Horizontal whitespace (spaces, tabs) – not newlines. | | newline | Line‑break characters (CR, LF, CRLF). | | undefined | Any other character (should not occur in valid JSON; used as fallback). | Important Notes No recursion – the regex only tokenises; the parser handles nesting and depth limits. Escaped characters inside strings (\n, \t, \", etc.) are not unescaped by the regex – the parser calls UnEscape() when _allowEscapeChars is true. Whitespace and newlines are ignored by the parser (skipped during token iteration). The undefined group uses .+ (not .*) to avoid matching empty positions – this prevents false positives when the scanner reaches the end of the string. Purpose This regex is a solid foundation for building a custom JSON lexer, parser, or tokeniser for .NET projects. Its clear separation of structural elements, comments, and whitespace makes it easy to implement lightweight, hand‑crafted parsers that do not rely on heavy external libraries. It is particularly well‑suited for small to medium‑sized files, configuration blocks, or embedded data fragments, where performance and memory footprint matter. You can adapt the token stream to your own data model, add validation, or transform the JSON on the fly – all while keeping full control over the parsing logic.
Submitted by Pavel Bashkardin
1

ตรวจสอบพยัญชนะต้นตัวสะกดสระและวรรณยุกต์ไทย

Created·2026-01-22 01:36
Updated·2026-01-23 12:42
Type·Match
Flavor·JavaScript
ตรวจสอบพยัญชนะต้น (ต้องมี) ตรวจตัวสะกดสำหรับสระที่ต้องมี ตรวจสอบการวางสระและวรรณยุกต์ไทย หมายเหตุ การตรวจสอบตัวสะกดในภาษาไทยตรวจสอบได้ยากเพราะภาษาไทยเป็นภาษาที่เขียนติด ๆ กันไม่มีการแบ่งคำอย่างชัดเจนทำให้การอ่านภาษาไทยผู้อ่านต้องใช้ความหมายของคำในการตัดสินการอ่านแบ่งคำตามความเหมาะสมเช่นคำว่า "ตากลม" อาจอ่านเป็น "ตาก-ลม" ก็ได้ หรืออ่านเป็น "ตา-กลม"ก็ได้ ดังนั้นการเขียน Regex เพื่อทำการตรวจสอบอาจช่วยได้ระดับหนึ่ง อ่าจมีผิดบ้างถูกบ้าง แต่ก็ถือว่าเป็นเครื่องมือที่ใช้ช่วยเหลือในการตรวจสอบเพิ่มเติมได้ 80% ของความเป็นไปใด้ก็แล้วกันนะครับ หวังว่าการเขียนเพิ่มเติมส่วนนี้ จะมีประโยชน์บ้างไม่มากก็น้อย
Submitted by อธิปัตย์ ล้อวงศ์งาม

Community Library Entry

1

Regular ExpressionOpen Workspace

/
(?(DEFINE) (?<add> \s*\+\s* ) (?<eq> \s*=\s* ) # Remove all zeroes except the last one if the number is 0 (?<zero> (?:0(?=\d))*+ ) # cl: last digit of left operand being 1, cr: last digit of right operand being 1, \d(?:0|\b) check if last digit from result is 0 # there will be carry if cl and cr are set, or cl or cr are set and the last digit from result is 0 (?<carry> (?(cl)(?(cr)|\d(?:0|\b))|(?(cr)\d(?:0|\b)|(*F))) ) # add carry with l1 (current digit of left operand being 1) and r1 (current digit of right operand being 1) # i.e. returns result of carry + l1 + r1 in Z/2Z (?<digitadd> (?(?= (?(?=(?(l1)(?(r1)|(*F))|(?(r1)(*F))))(?&carry)|(?!(?&carry))) )1|0) ) # check for a single digit at the current offset whether the result is correct # ro: right operand out of bounds (i.e. the current digit is at a higher offset than the size of the left operand) # if we're out of bounds of the right operand, cr is just not set (i.e. handled as if there were leading zeroes) (?<recursedigit> # now, with the r and f, we can figure out r1 and cr at the current offset and also perform binary carry addition at that offset in the result (?&add) (?&zero) (?:\d*(?:0|1(?<r1>)))? (?(ro)|(?=(?<cr>1)?))\k<r> (?&eq) \d*(?&digitadd)\k<f>\b # iterate through the whole left operand to find the sequences (for right operand and result) of the same length as the offset of the current digit | (?=\d* (?&add) (?&zero) (?:\k<r>(?<ro>)|\d*(?<r>\d\k<r>)) (?&eq) \d*(?<f>\d\k<f>)\b) \d(?&recursedigit) ) # run the check, sets l1 and cl accordingly and initializes the r (right operand) and f (final result) groups to be empty (?<checkdigit> (?:0|1(?<l1>)) (?=(?<cl>1)?) (?<r>) (?<f>) (?&recursedigit) ) # "trivial" increment of a binary number, i.e. a +1 is applied to the part of the right operand which exceeds the length of the left operand (?<carryoverflow> # number contains a zero, just update the part after the last zero (?<x>\d+) 0 (?<y> \k<r> (?&eq) 0*\k<x>1 | 1(?&y)0 ) # number contains only ones, add a leading 1 and replace all the ones by zeroes | (?<z> 1\k<r> (?&eq) 0*10 | 1(?&z)0 ) ) # ensure correct lengths of the final operand and handle right operands being longer than the left operand (?<recurseoverflow> # the left operand is longer than or as long as the right one. In the latter case, the final result will always be exactly one digit longer than the operands # in the former case, if the first non-leading zero (from the left) of the left operand is at a higher or equal offset to the length of the right operand, the final result will be one digit longer than the left operand (?&add) 0*+ (?(rlast) \k<r> (?&eq) 0*(?(ro)(?(addone)1)|1)\k<f>\b # the right operand has a zero at the offset equal to the length of the left operand. Then just copy the leading digits to the final result | (?:(?<remaining>\d+)(?=0\d* (?&eq) \d*(?=1)\k<f>\b)\k<r> (?&eq) (*PRUNE) 0*\k<remaining>\k<f>\b # otherwise there will be some carry which needs to be applied before copying the leading digits to the final result | (?&carryoverflow)\k<f>\b)) # iterate through the whole left operand to find the sequences (for right operand and result) of the same length as the left operand | (?=\d* (?&add) 0*+ (?:\k<r>(?<ro>)|(?=(?:\d\k<r>(?&eq)(?<rlast>))?)\d*(?<r>\d\k<r>)) (?&eq) \d*(?<f>\d\k<f>)\b) # check - only at the first non-leading zero - whether the right operand is longer than the current offset of the iteration, or just as long and having a carry (i.e. the digit at that offset in the final result is 0) (?(nullchecked)|(?=(?<addone>(?=0)(?=(?:\d(?=\d*(?&add)\d*(?&eq)\d*(?<c>\d\k<c>)\b))+(?&add))(?<longer>(?&add)0*|\d(?&longer)\d)(\d+(?&eq)|(?&eq)\d*(?=0)\k<c>))?)(?=(?<nullchecked>0)?)) \d(?&recurseoverflow) ) (?<s> (?=\d) 0*? (?<arg>[01]+)? (?&add) (?=\d) 0*? (?<arg>(?(arg)(*F))[01]+)? (?&eq) (*PRUNE) \k<arg> | (?&zero) # traverse the digits one by one and verify the correctness of each offset individually (?=(?<iteratedigits> (?=(?&checkdigit))\d (?:\b|(?&iteratedigits)) )) # assert exact format here (?=[01]+ (?&add) [01]+ (?&eq) [01]+ \b) # remove leading zeroes and force an additional digit on the final result in case the left operand is only ones and the right operand not longer than the left 0*? (?<r>) (?<f>) (?<c>) (?=(?<addone>1+(?&add))?) (?&recurseoverflow) # Handle 0 + x or x + 0 separately to avoid messing around in the big subpatterns ) ) \b(?&s)\b
/
xgJ

Description
Created·2016-09-15 02:03
Type·Match
Flavor·PCRE (Legacy)

Verifies whether two binary numbers a and b are equal to their sum c; Input expected in form a + b = c

Submitted by Bob Weinand
Open Workspace