create hash out of a recursive string in perl

Posted on 2008-10-20
Last Modified: 2012-05-05
I have the following string(s)and I want to generate a hash of hash from this one.

;&EVENT[__nmi_0](nmi, THREAD => 0, TRIGGER => &TRIGGER[__nmi_0.trigger](eom, LIP => 0x2020, SELF_CHECK => 'MUST_COMPLETE', THREAD => 0));

Hash %Event might look like this:

Event[nmi_0][event] = nmi
Event[nmi_0][Thread] =0
Event[nmi_0][Trigger] = __nmi_0.trigger
Event[nmi_0][__nmi_0.trigger][trigger] = eom
Event[nmi_0][__nmi_0.trigger][LIP] = 0x2020
Event[nmi_0][__nmi_0.trigger][SELF_CHECK] = 'MUST_COMPLETE'
Event[nmi_0][__nmi_0.trigger][THREAD] = 0

Below is an example of recursive strings.

;&EVENT[__psmi_1](psmi, THREAD => 0, TRIGGER => &TRIGGER[__retire_1](retire, LIP => 0x203f, TRIGGER => &EVENT[__smi_1](smi, THREAD => 1, TRIGGER => &TRIGGER[__eom_1](eom, LIP => 0x203f, THREAD => 0))));

Event[psmi_0][event] = psmi
Event[nmi_0][Thread] =0
Event[nmi_0][Trigger] = __retire_0.trigger
Event[nmi_0][__retire_0.trigger][trigger] = retire
Event[nmi_0][__retire_0.trigger][LIP] = 0x203f
Event[nmi_0][__nmi_0.trigger][trigger] = smi_1
Event[nmi_0][__nmi_0.trigger][smi_1][event] = smi
Event[nmi_0][__nmi_0.trigger][smi_1][Thread] = 0
Event[nmi_0][__nmi_0.trigger][smi_1][Trigger] = eom_1
Event[nmi_0][__nmi_0.trigger][smi_1][eom_1][event] = eom
Event[nmi_0][__nmi_0.trigger][smi_1][eom_1][Thread] = 0
Event[nmi_0][__nmi_0.trigger][smi_1][eom_1][LIP] = 0x203f

Can someone show me how to do hash like this? The string can have these events and triggers nested any number of times my hash has to build accordingly.

Question by:Anu2117
  • 2

Author Comment

ID: 22761307
Event[psmi_0][event] = psmi
Event[psmi_0][Thread] =0
Event[psmi_0][Trigger] = __retire_0.trigger
Event[psmi_0][__retire_0.trigger][trigger] = retire
Event[psmi_0][__retire_0.trigger][LIP] = 0x203f
Event[psmi_0][__retire_0.trigger][trigger] = smi_1
Event[psmi_0][__retire_0.trigger][smi_1][event] = smi
Event[psmi_0][__retire_0.trigger][smi_1][Thread] = 0
Event[psmi_0][__retire_0.trigger][smi_1][Trigger] = eom_1
Event[psmi_0][__retire_0.trigger][smi_1][eom_1][event] = eom
Event[psmi_0][__retire_0.trigger][smi_1][eom_1][Thread] = 0
Event[psmi_0][__retire_0.trigger][smi_1][eom_1][LIP] = 0x203f

I made a mistake in my example hash, here is the correct hash interpretation for the string. This the 2nd example in my question above.
LVL 39

Accepted Solution

Adam314 earned 500 total points
ID: 22761803
Your expected data doesn't seem consistent with your input string... but accounting for possible typos
use strict;
use warnings;
use Data::Dumper;
my @str = (";&EVENT[__nmi_0](nmi, THREAD => 0, TRIGGER => &TRIGGER[__nmi_0.trigger](eom, LIP => 0x2020, SELF_CHECK => 'MUST_COMPLETE', THREAD => 0));",
           ";&EVENT[__psmi_1](psmi, THREAD => 0, TRIGGER => &TRIGGER[__retire_1](retire, LIP => 0x203f, TRIGGER => &EVENT[__smi_1](smi, THREAD => 1, TRIGGER => &TRIGGER[__eom_1](eom, LIP => 0x203f, THREAD => 0))));");
my %Event;
my %Pieces;
foreach (@str) {
	%Pieces = ();
	my $Cnt;
	1 while s/\&(\w+)\[__([^\]]+)\]\((\w+),\s+([^\(\)]+)\)/print "String=$_\n";$Cnt++;$Pieces{$Cnt}=MakeHash($1,$2,$3,$4);"$2:SubHash{$Cnt}"/ge;
	for my $piece (sort {$b <=> $a} keys %Pieces) {
		while(my ($k, $v) = each %{$Pieces{$piece}}) {
			if($v =~ /^(.*):SubHash{(\d+)}$/) {
	if(/^;(.*):SubHash{(\d+)};$/) {
print Dumper(\%Event);
sub MakeHash {
	print "MakeHash(" . join("; ", @_) . ")\n";
	return {lc($_[0])=> $_[2], split(/[,=>\s]+/, $_[3])};

Open in new window


Author Closing Comment

ID: 31507961

    The ultimate use of this hash is to pass it as an argument to xml::simple::xmlout() so, I can get an xml output of this hash. But I am not getting that desired output right. This hash looks almost like an example hash in xmlout() help, but the xml is not like what is expected. I will file another ticket for this. If you get a chance, please take a look. Thanks a lot for the help.
LVL 84

Expert Comment

ID: 22762516
use Data::Dumper;
$_=q;&EVENT[__psmi_1](psmi, THREAD => 0, TRIGGER => &TRIGGER[__retire_1](retire, LIP => 0x203f, TRIGGER => &EVENT[__smi_1](smi, THREAD => 1, TRIGGER => &TRIGGER[__eom_1](eom, LIP => 0x203f, THREAD => 0))));;
$Event=mkhash("event","psmi_0 => $_");
sub mkhash{
    my %h;
    (my $re=$h)=~s/((\()|(\))|[^()]+)/${[')','']}[!$3]\Q$1\E${['(','']}[!$2]/gs;  
    $re=join'|',map quotemeta,$h=~/$re/;
    while( $h=~/(?:(\w+)\s*=>\s*)?(?:&(\w+)\[(\w+)\]\(($re)\)|(\w+)|'([^'']*)')/g ){
my $x=$3?"$3.\L$2":$1||$n;

    return \%h;
print Dumper $Event;

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
In the distant past (last year) I hacked together a little toy that would allow a couple of Manager types to query, preview, and extract data from a number of MongoDB instances, to their tool of choice: Excel (…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

860 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question