According to Regex documentation, using RegexOptions.ExplicitCapture makes the Regex only match named groups like (?<groupName>...); but in action it does something a little bit different.
Consider these lines of code:
static void Main(string[] args) {
Regex r = new Regex(
#"(?<code>^(?<l1>[\d]{2})/(?<l2>[\d]{3})/(?<l3>[\d]{2})$|^(?<l1>[\d]{2})/(?<l2>[\d]{3})$|(?<l1>^[\d]{2}$))"
, RegexOptions.ExplicitCapture
);
var x = r.Match("32/123/03");
r.GetGroupNames().ToList().ForEach(gn => {
Console.WriteLine("GroupName:{0,5} --> Value: {1}", gn, x.Groups[gn].Success ? x.Groups[gn].Value : "");
});
}
When you run this snippet you'll see the result contains a group named 0 while I don't have a group named 0 in my regex!
GroupName: 0 --> Value: 32/123/03
GroupName: code --> Value: 32/123/03
GroupName: l1 --> Value: 32
GroupName: l2 --> Value: 123
GroupName: l3 --> Value: 03
Press any key to continue . . .
Could somebody please explain this behavior to me?
You always have group 0: that's the entire match. Numbered groups are relative to 1 based on the ordinal position of the opening parenthesis that defines the group. Your regular expression (formatted for clarity):
(?<code>
^
(?<l1> [\d]{2} )
/
(?<l2> [\d]{3} )
/
(?<l3> [\d]{2} )
$
|
^
(?<l1>[\d]{2})
/
(?<l2>[\d]{3})
$
|
(?<l1> ^[\d]{2} $ )
)
Your expression will backtrack, so you might consider simplifying your regular expression. This is probably clearer and more efficient:
static Regex rxCode = new Regex(#"
^ # match start-of-line, followed by
(?<code> # a mandatory group ('code'), consisting of
(?<g1> \d\d ) # - 2 decimal digits ('g1'), followed by
( # - an optional group, consisting of
/ # - a literal '/', followed by
(?<g2> \d\d\d ) # - 3 decimal digits ('g2'), followed by
( # - an optional group, consisting of
/ # - a literal '/', followed by
(?<g3> \d\d ) # - 2 decimal digits ('g3')
)? # - END: optional group
)? # - END: optional group
) # - END: named group ('code'), followed by
$ # - end-of-line
" , RegexOptions.IgnorePatternWhitespace|RegexOptions.ExplicitCapture );
Once you have that, something like this:
string[] texts = { "12" , "12/345" , "12/345/67" , } ;
foreach ( string text in texts )
{
Match m = rxCode.Match( text ) ;
Console.WriteLine("{0}: match was {1}" , text , m.Success ? "successful" : "NOT successful" ) ;
if ( m.Success )
{
Console.WriteLine( " code: {0}" , m.Groups["code"].Value ) ;
Console.WriteLine( " g1: {0}" , m.Groups["g1"].Value ) ;
Console.WriteLine( " g2: {0}" , m.Groups["g2"].Value ) ;
Console.WriteLine( " g3: {0}" , m.Groups["g3"].Value ) ;
}
}
produces the expected
12: match was successful
code: 12
g1: 12
g2:
g3:
12/345: match was successful
code: 12/345
g1: 12
g2: 345
g3:
12/345/67: match was successful
code: 12/345/67
g1: 12
g2: 345
g3: 67
named group
^(?<l1>[\d]{2})/(?<l2>[\d]{3})/(?<l3>[\d]{2})$|^(?<l1>[\d]{2})/(?<l2>[\d]{3})$|(?<l1>^[\d]{2}$)
try this (i remove first group from your regex) - see demo
Related
I'm looking for a .NET Regex pattern that matches the following:
string starts with the [ character
followed by an integer or decimal number
followed by .. (space character, dot, dot, space character)
followed by an integer or decimal number
followed by the last character of the string which is )
*- the decimal numbers have a decimal separator, the . character
*- the integer numbers or the integer value of the decimal numbers should have a maximum of 4 digits
*- the decimal numbers should have a maximum of 4 fractional digits
*- the numbers can be negative
*- if a number is positive then the + sign is missing
*- doesn't matter which one of the two numbers is smaller (first number can be bigger than the second one, "[56 .. 55)" for instance)
The pattern should match the following:
"[10 .. 15)"
"[100 .. 15.2)"
"[10.431 .. 15)"
"[-10.3 .. -5)"
"[-10.4 .. 5.12)"
"[10.4312 .. -5.1232)"
I'd also like to obtain the 2 numbers as strings from the string in case the pattern matches:
obtain "10" and "15" from "[10 .. 15)"
obtain "-10.4" and "5.12" from "[-10.4 .. 5.12)"
The following regex should be fine.
^\[-?\d+(?:\.\d+)? \.\. -?\d+(?:\.\d+)?\)$
var pattern = #"^\[-?\d+(?:\.\d+)? \.\. -?\d+(?:\.\d+)?\)$";
var inputs = new[]{"[10 .. 15)", "[100 .. 15.2)", "[10.431 .. 15)", "[-10.3 .. -5)", "[-10.4 .. 5.12)", "[10.4312 .. -5.1232)", };
foreach (var input in inputs)
{
Console.WriteLine(input + " = " + Regex.IsMatch(input, pattern));
}
// [10 .. 15) = True
// [100 .. 15.2) = True
// [10.431 .. 15) = True
// [-10.3 .. -5) = True
// [-10.4 .. 5.12) = True
// [10.4312 .. -5.1232) = True
https://dotnetfiddle.net/LpswtI
You can use
^\[(-?\d{1,4}(?:\.\d{1,4})?) \.\. (-?\d{1,4}(?:\.\d{1,4})?)\)$
See the regex demo. Details:
^ - start of string
\[ - a [ char
(-?\d{1,4}(?:\.\d{1,4})?) - Group 1: an optional -, one to four digits and then an optional sequence of a . and one to four digits
\.\. - a .. string
(-?\d{1,4}(?:\.\d{1,4})?) - Group 2: an optional -, one to four digits and then an optional sequence of a . and one to four digits
\) - a ) char
$ - end of string (use \z if you need to check for the very end of string).
See the C# demo:
var texts = new List<string> { "[10 .. 15)", "[100 .. 15.2)", "[10.431 .. 15)", "[-10.3 .. -5)", "[-10.4 .. 5.12)", "[10.4312 .. -5.1232)", "[12345.1234 .. 0)", "[1.23456 .. 0" };
var pattern = new Regex(#"^\[(-?\d{1,4}(?:\.\d{1,4})?) \.\. (-?\d{1,4}(?:\.\d{1,4})?)\)$");
foreach (var s in texts)
{
Console.WriteLine($"---- {s} ----");
var match = pattern.Match(s);
if (match.Success)
{
Console.WriteLine($"Group 1: {match.Groups[1].Value}, Group 2: {match.Groups[2].Value}");
}
else
{
Console.WriteLine($"No match found in '{s}'.");
}
}
Output:
---- [10 .. 15) ----
Group 1: 10, Group 2: 15
---- [100 .. 15.2) ----
Group 1: 100, Group 2: 15.2
---- [10.431 .. 15) ----
Group 1: 10.431, Group 2: 15
---- [-10.3 .. -5) ----
Group 1: -10.3, Group 2: -5
---- [-10.4 .. 5.12) ----
Group 1: -10.4, Group 2: 5.12
---- [10.4312 .. -5.1232) ----
Group 1: 10.4312, Group 2: -5.1232
---- [12345.1234 .. 0) ----
No match found in '[12345.1234 .. 0)'.
---- [1.23456 .. 0 ----
No match found in '[1.23456 .. 0'.
This works (see this .Net Fiddle:
using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
Match m = rx.Match("[123 .. -9876.5432]");
if (!m.Success )
{
Console.WriteLine("No Match");
}
else
{
Console.WriteLine(#"left: {0}", m.Groups[ "left" ] );
Console.WriteLine(#"right: {0}", m.Groups[ "right" ] );
}
}
private static readonly Regex rx = new Regex(#"
^ # anchor match at start-of-text
[[] # a left square bracket followed by
(?<left> # a named capturing group, containing a number, consisting of
-?[0-9]{1,4} # - a mandatory integer portion followed by
([.][0-9]{1,4})? # - an optional fractional portion
) # the whole of which is followed by
[ ][.][.][ ] # a separator (' .. '), followed by
(?<right> # another named capturing group containing a number, consisting of
-?[0-9]{1,4} # - a mandatory integer portion followed by
([.][0-9]{1,4})? # - an optional fractional portion
) # the whole of which is followed by
\] # a right square bracket, followed by
$ # end-of-text
",
RegexOptions.IgnorePatternWhitespace|RegexOptions.ExplicitCapture
);
}
I'm trying to replace '&' inside quotes.
Input
"I & my friends are stuck here", & we can't resolve
Output
"I and my friends are stuck here", & we can't resolve
Replace '&' by 'and' and only inside quotes, could you please help?
By far the quickest way is to use the \G construct and do it with a single regex.
C# code
var str =
"\"I & my friends are stuck here & we can't get up\", & we can't resolve\n" +
"=> \"I and my friends are stuck here and we can't get up\", & we can't resolve\n";
var rx = #"((?:""(?=[^""]*"")|(?<!""|^)\G)[^""&]*)(?:(&)|(""))";
var res = Regex.Replace(str, rx, m =>
// Replace the ampersands inside double quotes with 'and'
m.Groups[1].Value + (m.Groups[2].Value.Length > 0 ? "and" : m.Groups[3].Value));
Console.WriteLine(res);
Output
"I and my friends are stuck here and we can't get up", & we can't resolve
=> "I and my friends are stuck here and we can't get up", & we can't resolve
Regex ((?:"(?=[^"]*")|(?<!"|^)\G)[^"&]*)(?:(&)|("))
https://regex101.com/r/db8VkQ/1
Explained
( # (1 start), Preamble
(?: # Block
" # Begin of quote
(?= [^"]* " ) # One-time check for close quote
| # or,
(?<! " | ^ ) # If not a quote behind or BOS
\G # Start match where last left off
)
[^"&]* # Many non-quote, non-ampersand
) # (1 end)
(?: # Body
( & ) # (2), Ampersand, replace with 'and'
| # or,
( " ) # (3), End of quote, just put back "
)
Benchmark
Regex1: ((?:"(?=[^"]*")|(?<!"|^)\G)[^"&]*)(?:(&)|("))
Completed iterations: 50 / 50 ( x 1000 )
Matches found per iteration: 10
Elapsed Time: 2.21 s, 2209.03 ms, 2209035 µs
Matches per sec: 226,343
Use
Regex.Replace(s, "\"[^\"]*\"", m => Regex.Replace(m.Value, #"\B&\B", "and"))
See the C# demo:
using System;
using System.Linq;
using System.Text.RegularExpressions;
public class Test
{
public static void Main()
{
var s = "\"I & my friends are stuck here\", & we can't resolve";
Console.WriteLine(
Regex.Replace(s, "\"[^\"]*\"", m => Regex.Replace(m.Value, #"\B&\B", "and"))
);
}
}
Output: "I and my friends are stuck here", & we can't resolve
I have this RegEx for C# ASP.NET MVC3 Model validation:
[RegularExpression(#"[0-9]*\,?[0-9]?[0-9]")]
This works for almost all cases, except if the number is bigger than 100.
Any number greater than 100 should show error.
I already tried use [Range], but it doesn't work with commas.
Valid: 0 / 0,0 / 0,00 - 100 / 100,0 / 100,00.
Invalid (Number > 100).
Not sure if zero's are only optional digits at the end but
# (?:100(?:,0{1,2})?|[0-9]{1,2}(?:,[0-9]{1,2})?)
(?:
100
(?: , 0{1,2} )?
|
[0-9]{1,2}
(?: , [0-9]{1,2} )?
)
Zero's only option at end
# (?:100|[0-9]{1,2})(?:,0{1,2})?
(?:
100
| [0-9]{1,2}
)
(?: , 0{1,2} )?
And, the permutations for no leading zero's except for zero itself
# (?:100(?:,0{1,2})?|(?:0|[1-9][0-9]?)(?:,[0-9]{1,2})?)
(?:
100
(?: , 0{1,2} )?
|
(?:
0
|
[1-9] [0-9]?
)
(?: , [0-9]{1,2} )?
)
# (?:100|0|[1-9][0-9])(?:,0{1,2})?
(?:
100
|
0
|
[1-9] [0-9]
)
(?: , 0{1,2} )?
Here's a RegEx that matches your criteria:
^(?:(?:[0-9]|[1-9]{1,2})(?:,[0-9]{1,2})?|(?:100)(?:,0{1,2})?)$
(Given your use case, I have assumed that your character sequence appears by itself and is not embedded within other content. Please let me know if that is not the case.)
And here's a Perl program that demonstrates that RegEx on a sample data set. (Also see live demo.)
#!/usr/bin/env perl
use strict;
use warnings;
while (<DATA>) {
chomp;
# A1 => An integer between 1 and 99, without leading zeros.
# (Although zero can appear by itself.)
#
# A2 => A optional fractional component that may contain no more
# than two digits.
#
# -OR-
#
# B1 => The integer 100.
#
# B2 => A optional fractional component following that may
# consist of one or two zeros only.
#
if (/^(?:(?:[0-9]|[1-9]{1,2})(?:,[0-9]{1,2})?|(?:100)(?:,0{1,2})?)$/) {
# ^^^^^^^^A1^^^^^^ ^^^^^A2^^^^ ^B1 ^^^B2^^
print "* [$_]\n";
} else {
print " [$_]\n";
}
}
__DATA__
0
01
11
99
100
101
0,0
0,00
01,00
0,000
99,00
99,99
100,0
100,00
100,000
100,01
100,99
101,00
Expected Output
* [0]
[01]
* [11]
* [99]
* [100]
[101]
* [0,0]
* [0,00]
[01,00]
[0,000]
* [99,00]
* [99,99]
* [100,0]
* [100,00]
[100,000]
[100,01]
[100,99]
[101,00]
I have an expression:
((((the&if)|sky)|where)&(end|finish))
What I need is to put a space between symbols and words so that it ends up like:
( ( ( ( the & if ) | sky ) | where ) & ( end | finish ) )
The regex I came up with is (\w)*[(\&*)(\|*)] which only gets me:
( ( ( ( the& if) | sky) | where) & ( end| finish) )
Could I get a little help here from a resident regex guru please? I will be using this in C#.
Edit: Since you're using C#, try this:
output = Regex.Replace(input, #"([^\w\s]|\w(?!\w))(?!$)", "$1 ");
That inserts a space after any character that matches the following conditions:
Is neither a letter, number, underscore, or whitespace
OR is a word character that is NOT followed by another word character
AND is not at the end of a line.
resultString = Regex.Replace(subjectString, #"\b|(?<=\W)(?=\W)", " ");
Explanation:
\b # Match a position at the start or end of a word
| # or...
(?<=\W) # a position between two
(?=\W) # non-word characters
(and replace those with a space).
You could just add a space after each word and after each non-word character (so look for \W|\w+ and replace it with the match and a space. e.g. in Vim:
:s/\W\|\w\+/\0 /g
You could use:
(\w+|&|\(|\)|\|)(?!$)
which means a word, or a & symbol, or a ( symbol, or a ) symbol, or a | symbol not followed by an end of string; and then replace a match with a match + space symbol. By using c# this could be done like:
var result = Regex.Replace(
#"((((the&if)|sky)|where)&(end|finish))",
#"(\w+|&|\(|\)|\|)(?!$)",
"$+ "
);
Now result variable contains a value:
( ( ( ( the & if ) | sky ) | where ) & ( end | finish ) )
I hope you guys can help me out.
I'm using C# .Net 4.0
I want validate file structure like
const string dataFileScr = #"
Start 0
{
Next = 1
Author = rk
Date = 2011-03-10
/* Description = simple */
}
PZ 11
{
IA_return()
}
GDC 7
{
Message = 6
Message = 7
Message = 8
Message = 8
RepeatCount = 2
ErrorMessage = 10
ErrorMessage = 11
onKey[5] = 6
onKey[6] = 4
onKey[9] = 11
}
";
So far I managed to build this regex pattern
const string patternFileScr = #"
^
((?:\[|\s)*
(?<Section>[^\]\r\n]*)
(?:\])*
(?:[\r\n]{0,}|\Z))
(
(?:\{) ### !! improve for .ini file, dont take {
(?:[\r\n]{0,}|\Z)
( # Begin capture groups (Key Value Pairs)
(?!\}|\[) # Stop capture groups if a } is found; new section
(?:\s)* # Line with space
(?<Key>[^=]*?) # Any text before the =, matched few as possible
(?:[\s]*=[\s]*) # Get the = now
(?<Value>[^\r\n]*) # Get everything that is not an Line Changes
(?:[\r\n]{0,})
)* # End Capture groups
(?:[\r\n]{0,})
(?:\})?
(?:[\r\n\s]{0,}|\Z)
)*
";
and c#
Dictionary <string, Dictionary<string, string>> DictDataFileScr
= (from Match m in Regex.Matches(dataFileScr,
patternFileScr,
RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline)
select new
{
Section = m.Groups["Section"].Value,
kvps = (from cpKey in m.Groups["Key"].Captures.Cast().Select((a, i) => new { a.Value, i })
join cpValue in m.Groups["Value"].Captures.Cast().Select((b, i) => new { b.Value, i }) on cpKey.i equals cpValue.i
select new KeyValuePair(cpKey.Value, cpValue.Value)).OrderBy(_ => _.Key)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
}).ToDictionary(itm => itm.Section, itm => itm.kvps);
It works for
const string dataFileScr = #"
Start 0
{
Next = 1
Author = rk
Date = 2011-03-10
/* Description = simple */
}
GDC 7
{
Message = 6
RepeatCount = 2
ErrorMessage = 10
onKey[5] = 6
onKey[6] = 4
onKey[9] = 11
}
";
in other words
Section1
{
key1=value1
key2=value2
}
Section2
{
key1=value1
key2=value2
}
, but
1. not for multiple keyname, i want group by key and output
DictDataFileScr["GDC 7"]["Message"] = "6|7|8|8"
DictDataFileScr["GDC 7"]["ErrorMessage"] = "10|11"
2. not work for .ini file like
....
[Section1]
key1 = value1
key2 = value2
[Section2]
key1 = value1
key2 = value2
...
3. dont see next section after
....
PZ 11
{
IA_return()
}
.....
Here is a complete rework of the regex in C#.
Assumptions : (tell me if one of them is false or all are false)
An INI file section can only have key/value pair lines in its body
In an non INI file section, function calls can't have any parameters
Regex flags :
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled | RegexOptions.Singleline
Input test:
const string dataFileScr = #"
Start 0
{
Next = 1
Author = rk
Date = 2011-03-10
/* Description = simple */
}
PZ 11
{
IA_return()
}
GDC 7
{
Message = 6
Message = 7
Message = 8
Message = 8
RepeatCount = 2
ErrorMessage = 10
ErrorMessage = 11
onKey[5] = 6
onKey[6] = 4
onKey[9] = 11
}
[Section1]
key1 = value1
key2 = value2
[Section2]
key1 = value1
key2 = value2
";
Reworked regex:
const string patternFileScr = #"
(?<Section> (?# Start of a non ini file section)
(?<SectionName>[\w ]+)\s* (?# Capture section name)
{ (?# Match but don't capture beginning of section)
(?<SectionBody> (?# Capture section body. Section body can be empty)
(?<SectionLine>\s* (?# Capture zero or more line(s) in the section body)
(?: (?# A line can be either a key/value pair, a comment or a function call)
(?<KeyValuePair>(?<Key>[\w\[\]]+)\s*=\s*(?<Value>[\w-]*)) (?# Capture key/value pair. Key and value are sub-captured separately)
|
(?<Comment>/\*.+?\*/) (?# Capture comment)
|
(?<FunctionCall>[\w]+\(\)) (?# Capture function call. A function can't have parameters though)
)\s* (?# Match but don't capture white characters)
)* (?# Zero or more line(s), previously mentionned in comments)
)
} (?# Match but don't capture beginning of section)
)
|
(?<Section> (?# Start of an ini file section)
\[(?<SectionName>[\w ]+)\] (?# Capture section name)
(?<SectionBody> (?# Capture section body. Section body can be empty)
(?<SectionLine> (?# Capture zero or more line(s) in the section body. Only key/value pair allowed.)
\s*(?<KeyValuePair>(?<Key>[\w\[\]]+)\s*=\s*(?<Value>[\w-]+))\s* (?# Capture key/value pair. Key and value are sub-captured separately)
)* (?# Zero or more line(s), previously mentionned in comments)
)
)
";
Discussion
The regex is build to match either non INI file sections (1) or INI file section (2).
(1) Non-INI file sections These sections are composed by a section name followed by a body enclosed by { and }.
The section name con contain either letters, digits or spaces.
The section body is composed by zero or more lines. A line can be either a key/value pair (key = value), a comment (/* Here is a comment */) or a function call with no parameters (my_function()).
(2) INI file sections
These sections are composed by a section name enclosed by [ and ] followed by zero or more key/value pairs. Each pair is on one line.
Do yourself and your sanity a favor and learn how to use GPLex and GPPG. They are the closest thing that C# has to Lex and Yacc (or Flex and Bison, if you prefer) which are the proper tools for this job.
Regular expressions are great tools for performing robust string matching, but when you want to match structures of strings that's when you need a "grammar". This is what a parser is for. GPLex takes a bunch of regular expressions and generates a super-fast lexer. GPPG takes the grammar you write and generates a super-fast parser.
Trust me, learn how to use these tools ... or any other tools like them. You'll be glad you did.
# 2. not work for .ini file like
Won't work because as stated by your regular expression, an { is required after [Section].
Your regex will match if you have something like this :
[Section]
{
key = value
}
Here is a sample in Perl. Perl doesen't have named capture arrays. Probably because of backtracking.
Maybe you can pick something out of the regex though. This assumes there is no nesting of {} bracktes.
Edit Never content to leave well enough alone, a revised version is below.
use strict;
use warnings;
my $str = '
Start 0
{
Next = 1
Author = rk
Date = 2011-03-10
/* Description = simple
*/
}
asdfasdf
PZ 11
{
IA_return()
}
[ section 5 ]
this = that
[ section 6 ]
this_ = _that{hello() hhh = bbb}
TOC{}
GDC 7
{
Message = 6
Message = 7
Message = 8
Message = 8
RepeatCount = 2
ErrorMessage = 10
ErrorMessage = 11
onKey[5] = 6
onKey[6] = 4
onKey[9] = 11
}
';
use re 'eval';
my $rx = qr/
\s*
( \[ [^\S\n]* )? # Grp 1 optional ini section delimeter '['
(?<Section> \w+ (?:[^\S\n]+ \w+)* ) # Grp 2 'Section'
(?(1) [^\S\n]* \] |) # Condition, if we matched '[' then look for ']'
\s*
(?<Body> # Grp 3 'Body' (for display only)
(?(1)| \{ ) # Condition, if we're not a ini section then look for '{'
(?{ print "Section: '$+{Section}'\n" }) # SECTION debug print, remove in production
(?: # _grp_
\s* # whitespace
(?: # _grp_
\/\* .*? \*\/ # some comments
| # OR ..
# Grp 4 'Key' (tested with print, Perl doesen't have named capture arrays)
(?<Key> \w[\w\[\]]* (?:[^\S\n]+ [\w\[\]]+)* )
[^\S\n]* = [^\S\n]* # =
(?<Value> [^\n]* ) # Grp 5 'Value' (tested with print)
(?{ print " k\/v: '$+{Key}' = '$+{Value}'\n" }) # KEY,VALUE debug print, remove in production
| # OR ..
(?(1)| [^{}\n]* ) # any chars except newline and [{}] on the condition we're not a ini section
) # _grpend_
\s* # whitespace
)* # _grpend_ do 0 or more times
(?(1)| \} ) # Condition, if we're not a ini section then look for '}'
)
/x;
while ($str =~ /$rx/xsg)
{
print "\n";
print "Body:\n'$+{Body}'\n";
print "=========================================\n";
}
__END__
Output
Section: 'Start 0'
k/v: 'Next' = '1'
k/v: 'Author' = 'rk'
k/v: 'Date' = '2011-03-10'
Body:
'{
Next = 1
Author = rk
Date = 2011-03-10
/* Description = simple
*/
}'
=========================================
Section: 'PZ 11'
Body:
'{
IA_return()
}'
=========================================
Section: 'section 5'
k/v: 'this' = 'that'
Body:
'this = that
'
=========================================
Section: 'section 6'
k/v: 'this_' = '_that{hello() hhh = bbb}'
Body:
'this_ = _that{hello() hhh = bbb}
'
=========================================
Section: 'TOC'
Body:
'{}'
=========================================
Section: 'GDC 7'
k/v: 'Message' = '6'
k/v: 'Message' = '7'
k/v: 'Message' = '8'
k/v: 'Message' = '8'
k/v: 'RepeatCount' = '2'
k/v: 'ErrorMessage' = '10'
k/v: 'ErrorMessage' = '11'
k/v: 'onKey[5]' = '6'
k/v: 'onKey[6]' = '4'
k/v: 'onKey[9]' = '11'
Body:
'{
Message = 6
Message = 7
Message = 8
Message = 8
RepeatCount = 2
ErrorMessage = 10
ErrorMessage = 11
onKey[5] = 6
onKey[6] = 4
onKey[9] = 11
}'
=========================================