正则表达式 perl


字符串操作符
. 用于连接字符串
use warning 开启per内置的警告信息,或者用-w参数
use diagnostics 查看更多编译信息或者用-Mdiagnostics参数

读到文件结尾end-of-line时,返回undef标志,用defined函数是否是undef状态。
标量都是单数(singular),列表与数组代表复数(plural)
列表(list)指的是标量的有序集合,而数组(array)则是存储列表的变量
或者说列表指的是数据,而数组指的是变量

$rocks[$#rocks]  $rocks[-1]等效 都指最后一个

("aaa","bbb","ccc","ddd")
qw(aaa,bbb,ccc,ddd)两等效

Perl允许使用任何标点符号作为定界符,常用的有:
qw! aaa bbb ccc ddd !
qw/ aaa bbb ccc ddd /
qw# aaa bbb ccc ddd #

@arrayname 引用整个数组
push-pop操作数组尾和shift-unshift操作数组首
splice
@array = qw(aaa,bbb,ccc,ddd,eee);
@removed = splice @array,2;
# @removed变成qw(ccc,ddd)
# @array变成qw(aaa,bbb)

foreach(1..10){
 print "this num is $_!\n"   #    $_ 默认变量
}

state来声明为当前子程序的持有性私有变量,并且多次调用这个子程序期间保留该变量的值。

chomp;  #不加参数,默认用默认参数$_

@ARGV #命令行默认参数

6个特殊文件句柄是Perl保留的,STDIN,STDOUT,STDERR,DATA,ARGV,ARGVOUT

数组用方括号,哈希用花括号
$hash{ 'index1' } = 'index1value';

哈希函数
$reverhash = revers %hash
my @k = keys %hash;
my @v = values %hash;
while(($key,$value) = each %hash)
{}
exists/delete

%ENV
print "PATH is $ENV{PATH}\n"

正则表达式
$_ = "yabba dabba doo";
if( /abba/ )
{..}

Unicode属性,Unicode字符能够理解自身含义,它们包含字节组合之外,还附带着属性信息。
if(/\q{Space}/){}
if(/\q{Digit}/){}

元字符
点号(.)是能匹配任意一个字符的通配符,换行符除外。
/3\.14159/这个模式中点号就不是表示通配的元字符
星号(*)正是用来匹配前面的条目零次或任意多次的
/abb\t*bbb/ 匹配abb\tbbb  abb\t\tbbb
/aaa.*bbb  因此会匹配任意字符零次到无限多次
加号(+)也是量词,会匹配前一个条目一次以上
问号(?),前面条目可出现一次或不出现
模式分组
/fred*/ 匹配freddddd
/(fred)*/ 匹配fredfred
反向引用来引用圆括号中的模式所柳丁的文字,这个行为我们称为捕获组,
比如\1 \2表示相应顺序的捕获组
$_ = "abb";
if(/(.)\1/){} #匹配 ‘bb'
/y(.)(.)\2\1/ #匹配 ’abba'
“aa11bb"
\111  是指\111,而不是\1或\11, Perl尽可能往多的原则靠
if(/(.)\g{1}11/) 指\1  解决反引用与直接量部分的二义性
if(/(.)\111/)   指\111
if(/(.)(.)\g{-1}11/ 相对自己的位置来找编号
择一匹配
/fred(|\t)+barney/
字符集,指的是一组可能出现的字符,通过写在方括号([])内表示。
[abcwxyx] 匹配7个字符内任意一个
[\000-\177] 将匹配任意一个7位的ASCII字符
[^def]会匹配这三个字符以外的任何字符   ^ 脱字符

字符集的简写
比如表示任意一个数字的字符集的简写是\d
\s简写能匹配任意空白符,所以效果上大抵等同于Unicode属性\p{Space}
Perl5.6之前,\s仅能匹配5个 换页符,水平制表符,换行符,回车符,空格
\h 只匹配水平空白符
\v 只匹配垂直空白符
\R简写能匹配任意一种断行符
\w能匹配的字符并不是严格意义上的单词字符
[^\d],[^\w],[^\s] 非数字,非单词或者非空白符
[\D],[\W],[\S] 大写版本表示否定意义

[\d\D],表示任何数字或非数字,也就是匹配任意字符(包含换行符),而点号不匹配换行符

正则表达式进行匹配
用m//进行匹配
/i进行大小写无关的匹配
/s匹配任意字符   点号无法匹配换行符,对单行点号就适用了
 $_ = "I saw Barney\ndown at the bowling alley\nwith fred\nlast night.\n"
 if(/Barney.*Fred/s){} 没有/s修饰符,匹配会失败。
/x加入空白符
 /-?[0-9]+\.?[0-9]*/
 / -? [0-9]+ \.? [0-9]* /x  #这样便于阅读,理解,但原来的空白和制表本身需要用\空格和\t
组合选项修饰符
 if(/barney.*fred/is){}

三种字符解释方式:ASCII(/a),Unicode(/u)和locale(l),locale经常会引发问题。

锚位,可以让模式仅在字符串指定位置匹配。
\A锚位匹配字符串的绝对开头,如果开头位置不匹配,是不会顺移到下一个位置继续尝试的。
m{\Ahttps?://}i  #判断字符串是否以https开头
m{\.png\z}i    #匹配以.png结尾的

字符串的绝对末尾,强调后面再无任何其他东西。 \Z允许后面出现换行符
while(<STDIN>){
 print if /\.png\Z/;
}

while(<STDIN>){
 chomp;
 print "$_\n" if /\.png\z/;
}

可以用$锚位和/m修饰符表示对多行内容进行匹配。
/fred$/m
单词锚位
/\bfred\b/可匹配fred,但无法匹配frederick,alfred,manfredss。\b是单词边界锚位,也称为”整词匹配“

绑定操作符=~
默认情况下模式匹配的操作对象是$_,绑定操作符(=~) 告诉perl用右边的模式来匹配左边的字符串。

模式中的内插
my $what = "larry";
while(<>){   #每次读一行输入
 if(/\A($what)/){ #模式的锚位被定在字符串的开头
  print "We saw $what in beginning of $_";
 }
}
除非while循环的条件表达式中只有整行输入操作符(<STDIN>) ,否则输入行不会被 PERL自动存入$_.

捕获变量
捕获组会把匹配圆括号中模式的字符串保存到相应的地方$1,$2,$3

$_ = "Hello there, neighbor";
if(/(\S+) (\S+),(\S+)/){
 print "word were $1 $2 $3\n";
}
运行结果是:words were Hello there neighbor.
捕获变量的存续期, 它们能戚到下次成功匹配为止。失败的匹配不会改动上次成功匹配时捕获的内容。

不捕获模式:用?:修饰的圆括号不会将捕获部分的匹配字符串放到捕获变量中
if(/(?:bronto)?saurs (steak|burger){
 print "Fred wants a $1\n";
}

命名捕获
my $names = 'Fred or Barney';
if( $names =~ m/(?<name1>\w+) (?:and|or) (?<name2>\w+/){
 say "i saw $+{name1} and $+{name2}";
}

自动捕获变量:$&,$`,$'免费但影响运行速度
字符串里实际匹配模式的部分会被自动在存进$&里
if( "Hello there, neighbor" =~ /\s(\w+),/){
 print "That actually matched '$&'.\n";
}
$1保存there
$&保存there,
匹配区段之前的内容会存到$`里,匹配区段之后的内容则会存到$'里

用/p修饰符则可用${^PREMATCH},${^MATCH}和${^POSTMATCH}表示。

用正则表达式处理文本
用s///进行替换
$_ = "He's out bowling with Barney tonight.";
s/Barney/Fred/; #把Barney替换为Fred
print "$_\n";

s/Barney/Fred/g; #/g 全局替换
my @filelds = split /separator/, $string;
my @fields = split /:/, "abc:def:g:h"; #得到("abc","def","g","h")

join函数功能与split相反
my $result = join $glue, @pieces;
my $x = join ":", 4,6,8,10,12; # $x为"4:6:8:10:12"

$_ = "Hello there, neighbor";
my($first,$second,$third) = /(\S+) (\S+), (\S+)/;
print "$second is my $third\n";

贪婪量词
/fred.+barney/  #要求能匹配的字符串越长越好
非贪婪量词
/fred.+?barney/  #要求能匹配的字符串越短越好

if(flag){...}   #flag为真时才执行
unless(flag){...} #flag为假时才执行

while(flag){...} #flag为真时才执行
until(flag){...} #flag为假时才执行

last操作符能立即中止循环的执行,相当C语言中的"break"
next相当continue
redo操作符返回到当前循环块的顶端,而不经过任何条件测试,也不会进入下一次循环迭代。

LINE:while(<>){
 foreach(split){
  last LINE if /__END__/;
  ...
 }
}

die "Oops! A file called '$filename' already exist.\n"
 if -e $filename;


PERL 模块
perldoc CGI 打开模块文档
perl自带cpan命令查看所有模块: $cpan -a

模块使用MakeMaker
$perl Makefile.PL
$make install

使用Module::Build
$perl Build.PL
$./Build install

perl自带的path::class模块则提供了更友好的操作界面:
my $dir  = dir( qw(Users fred lib) );
my $subdir= $dir ->subdir( 'perl5' ); # Users/fred/lib/perl5

DateTime处理日期和时间的模块

chdir操作符来改变当前的工作目录

my @all_files = <*>;
my @all_files = glob "*";

Perl里面,可以使用unlink操作符,并指定要删除的文件列表。
rename函数
chmod函数类似unix的chmod命令
chmod 0755, 'fred', 'barney';

字符串与排序
$where = index($big, $small);
 $big = "Howdy world!";
 $where = index($big, "wor");  # $where is 6 

my $part = substr($string, $initial_position, $length);
省略第三参数将取到字符串结尾
$initial_position  负数表示从后数起
substr($string, -20) =~ s/fred/barney/g; #  将后面20字符所有fred换成barney

sprintf函数与printf有相同的参数
my $date_tag = sprintf "%4d/%02d",$yr,$mo;

hex('DEA')
oct('0377')

智能匹配
use 5.010001
say "I found Fred in the name!" if $name ~~ /Fred/;
等价以下:
my $flag = 0;
foreach my $key (keys %names ){
 next unless $key =~ /Fred/;
 $flag = $key;
 last;
}
print "I found Fred in the name!" if $flag;

given-when类似switch

given ( $ARGV[0] ){
 when ( 'Fred' ){say 'Name is Fred' }
 when ( /fred/i ){say 'Name has fred in it' }
 defalut{say 'ss'}
}

进程管理
system 'date';  # perl调用unix的date命令。
exec

捕获错误
eval { $barney = $fred / $dino };
eval只是一个表达式,末尾加”;"
捕获到错误eval将返回undef,如果没有错误发生,$@就是空的
exit操作符会立即终止程度运行。

异常机制
die抛出异常
eval {
 ...;
 die "An unexpected exception message" if $unexpected;
 die "Bad denominator" if $dino == 0;
 $barney = $fred / $dino;
}
if( $@ =~ /unexpected/ ){
 ...;
}
elsif( $@ =~ /denominator/ ){
 ...;
}

{
local $@; #不干扰高层错误
...
}

foreach( 1..1000){
 push @odd_numbers, $_ if $_ % 2;
}
等价
my @odd_numbers = grep { $_ % 2 } 1..1000;

my @matching_lines = grep /\bfred\b/i, <$fh>;
my $line_count = @matching_lines;

my $line_count = grep /\bfred\b/i, <$fh>;

 

 

<!ELEMENT NXRMClientConfiguration (LocationArray,Log)>
<!ATTLIST NXRMClientConfiguration SchemaVersion CDATA #REQUIRED>
<!ATTLIST NXRMClientConfiguration SN CDATA #REQUIRED>
<!ATTLIST NXRMClientConfiguration Name CDATA #REQUIRED>
<!ATTLIST NXRMClientConfiguration UpdateDate CDATA #REQUIRED>
<!ELEMENT LocationArray (Location+)>
<!ELEMENT Location (#PCDATA)>
<!ATTLIST Location Name CDATA #Default>
<!ATTLIST Location Desc CDATA #REQUIRED>
<!ELEMENT Log (#PCDATA)>
<!ATTLIST Log MaxLogSize CDATA #REQUIRED>

 

#!/usr/bin/perl -w

#this sub function parser sub elment
#usage:
#$result = []; $subelement = "(A | (B, (C | (D, E))) | F)";
#Subelementparser($result,$subelement);
#return $result = A   B,C   B,D,E    F
sub Subelementparser{
 my($res,$temp)=@_;
 my($prematch,$match,$postmatch);
 my(@items);
 
 $temp =~ s/\s*//g;  # delete space
 $temp =~ s/^\((.*)\)$/$1/e; #delete outside bracket

 unless($temp =~ /\(/){  #case inside bracket
  if($temp =~ /\|/){
   @items = split(/\|/,$temp);
   foreach (@items){
    push @$res, $_;
   }
  }
  else{
   push @$res,$temp;
  }
 }
 else{   #case: there exist is one or more bracket
  $temp =~ m/\((.*)\)/;
  $prematch = ${^PREMATCH};
  $match = ${^MATCH};
  $postmatch = ${^POSTMATCH};
  
  $flag = "false";
  if($prematch =~ /,/){
   $flag = "true";
  }
  
  if($flag =~ /true/){  #case: B,(D|E)
   my($tempres) = [];
   Subelementparser($tempres,$match);
   foreach (@$tempres){
    push @$res, "${prematch}$_"; # $prematch = "B,"
   }
  }
  else{
   @items = split(/\|/,$prematch);
   foreach (@items){
    push @$res, "$_";
   }
   if($match =~ /./){
    Subelementparser($res,$match);
   }
  }
 
  @items = split(/\|/,$postmatch);
  foreach (@items){
   if(/./){
    push @$res, $_;
   }
  }
 }
}

sub ProcElement {
 my($cname, $expan)=@_;
 my($cinterdef,$cimpheader,$cimpcpp);
 my($construc, $parser);
 my($mem);
 my($headerfile,$class_name);

 my($subelements) = [];
 Subelementparser($subelements,$expan);

# here start generate .h file without attribute part and } end part
 $cinterdef = "// <!ELEMENT ${cname} ${expan}>\n";
 $cinterdef .= "class I$cname\n{\npublic:\n";
 $cinterdef .= "\tvirtual bool WriteToXML(const std::string& XMLPath) = 0;\n";
 $cinterdef .= "\tvirtual bool ReadFromXML(const std::string& XMLPath) = 0;\n";
 $cinterdef .= "\tvirtual void Reset(void) = 0;\n";
 $cinterdef .= "\tvirtual void Release(void) = 0;\n\n";
 
 $construc = "";
  
 $cimpheader = "class $cname : public I$cname\n{\npublic:\n";
 $cimpheader .= "\t$cname(void);\n";
 $cimpheader .= "\t$cname(const Node& node);\n";
 $cimpheader .= "\t~$cname(void);\n";
 $cimpheader .= "\tbool WriteToXML(const std::string& XMLPath);\n";
 $cimpheader .= "\tbool ReadFromXML(const std::string& XMLPath);\n";
 $cimpheader .= "\tvoid Reset(void);\n";
 $cimpheader .= "\tvoid Release(void);\n\n";

 $cimpcpp = "${cname}::${cname}() : m_node(Node())\n{\n\tm_node.SetNodeName(\"${cname}\");\n}\n\n";
 $cimpcpp .= "${cname}::${cname}(const Node& node) : m_node(node)\n{\n\tm_node.SetNodeName(\"${cname}\");\n}\n\n";
 $cimpcpp .= "${cname}::~${cname}(void)\n{\n}\n\n";
 $cimpcpp .= "bool ${cname}::WriteToXML(const std::string& XMLPath)\n{\n\treturn m_node.Print(XMLPath);\n}\n\n";
 $cimpcpp .= "bool ${cname}::ReadFromXML(const std::string& XMLPath)\n{\n\tm_node = Node(XMLPath);\n\treturn true;\n}\n\n";
 $cimpcpp .= "void ${cname}::Reset(void)\n{\n\tm_node = Node();\n\tm_node.SetNodeName(\"${cname}\");\n}\n\n";
 $cimpcpp .= "void ${cname}::Release(void)\n{\n\tdelete this;\n}\n\n";
 
 foreach (@$subelements){
  @subclass = split(/,/, $_);
#  $cdef .= "\t$cname(";
#  $flag = "false";
  foreach $mem (@subclass){
   if($mem =~ /[?*+]/){
    $mem =~ s/[*+?]//g;
    $cinterdef .= "\t//Element $mem\n";
    $cinterdef .= "\tvirtual unsigned int GetElem${mem}(void) = 0;\n";
      $cinterdef .= "\tvirtual I${mem}* GetElem${mem}At(unsigned int index) = 0;\n";
      $cinterdef .= "\tvirtual void AddElem${mem}(I${mem}* NewElem) = 0;\n";
      $cinterdef .= "\tvirtual void AddElem${mem}At(unsigned int index, I${mem}* NewElem) = 0;\n";
      $cinterdef .= "\tvirtual void RemoveElem${mem}At(unsigned int index) = 0;\n";
      $cinterdef .= "\tvirtual void RemoveAllElem${mem}(void) = 0;\n\n";
      
      $cimpheader .= "\t//Element $mem\n";
    $cimpheader .= "\tunsigned int GetElem${mem}(void);\n";
      $cimpheader .= "\tI${mem}* GetElem${mem}At(unsigned int index);\n";
      $cimpheader .= "\tvoid AddElem${mem}(I${mem}* NewElem);\n";
      $cimpheader .= "\tvoid AddElem${mem}At(unsigned int index, I${mem}* NewElem);\n";
      $cimpheader .= "\tvoid RemoveElem${mem}At(unsigned int index);\n";
      $cimpheader .= "\tvoid RemoveAllElem${mem}(void);\n\n";
      
      $cimpcpp .= "//Element $mem\n";
    $cimpcpp .= "unsigned int ${cname}::GetElem${mem}(void)\n{\n\treturn m_node.NumChilds();\n}\n\n";
      $cimpcpp .= "I${mem}* ${cname}::GetElem${mem}At(unsigned int index)\n{\n";
      $cimpcpp .= "\t${mem} *temp = NULL;\n\tunsigned int total = m_node.NumChilds();\n\tif(index < total)\n\t{\n";
      $cimpcpp .= "\t\ttemp = new ${mem}(m_node.GetChildAt(index));\n\t}\n\treturn temp;\n}\n\n";
      $cimpcpp .= "void ${cname}::AddElem${mem}(I${mem}* NewElem)\n{\n\tm_node.AppendChild(static_cast<${mem}*>(NewElem)->m_node);\n}\n\n";
      $cimpcpp .= "void ${cname}::AddElem${mem}At(unsigned int index, I${mem}* NewElem)\n{\n\tm_node.AppendChildAt(index,static_cast<${mem}*>(NewElem)->m_node);\n}\n\n";
      $cimpcpp .= "void ${cname}::RemoveElem${mem}At(unsigned int index)\n{\n\tm_node.RemoveChildAt(index);\n}\n\n";
      $cimpcpp .= "void ${cname}::RemoveAllElem${mem}(void)\n{\n\tm_node.RemoveChilds();\n}\n\n"; 
   }
   elsif($mem =~ /#PCDATA/){
   }
   else{
    $cinterdef .= "\t//Element $mem\n";
    $cinterdef .= "\tvirtual I${mem}* GetElem${mem}(void) = 0;\n";
    $cinterdef .= "\tvirtual void SetElem${mem}(I${mem}* ElemName) = 0;\n\n";
    
    $cimpheader .= "\t//Element $mem\n";
    $cimpheader .= "\tI${mem}* GetElem${mem}(void);\n";
    $cimpheader .= "\tvoid SetElem${mem}(I${mem}* ElemName);\n\n";
    
    $cimpcpp .= "//Element $mem\n";
    $cimpcpp .= "I${mem}* ${cname}::GetElem${mem}(void)\n{\n\treturn new ${mem}(m_node.GetFirstChild());\n}\n\n";
    $cimpcpp .= "void ${cname}::SetElem${mem}(I${mem}* ElemName)\n{\n\tm_node.AppendChild(static_cast<${mem}*>(ElemName)->m_node);\n}\n\n";
   }
  }
 }
 my(%hash) = ();
 undef %hash;
 foreach (@$subelements){
  @subclass = split(/,/, $_);
  foreach $mem (@subclass){
   if(/#PCDATA/){
#    $cdef .= "\tvoid addData( const std::string& data );\n";
   }
   else{
     unless(exists( $hash{ $mem} ))
     {
#      $cdef .= "\tvoid addNode( $mem *the_$mem );\n";
      
      $mem =~ s/[*+?]//g;
      $headerfile .= "#include \"${mem}.h\"\n";
      $class_name .= "class I${mem};\n";
      $hash{$mem} = 1;
     }
   }
  }
 }
 if($rootflag =~ /false/)
 {
  $construc .= "\nconst char* dtdData = \"$tempdtd\";\n\n";
#  $cdef .= "\tbool Validate() const;\n";
#  $cdef .= "\t$cname(const std::string& XMLFile);\n";
 }
# $cdef .= "};\n\n";  #wait for attribute
 
# here start generate .cpp file

 undef %hash;
 foreach (@$subelements){
  $construc .= "${cname}::${cname}(";
  @subclass = split(/,/, $_);
  $flag = "false";
  foreach $mem (@subclass){
   if( $flag =~ /true/ ){
    $construc .= ",";
   }
   if(/#PCDATA/){
    $construc .= " const std::string& data";
    $parser .= "void ${cname}::addData(const std::string& data)\n{\n";
    $parser .= "\tSetData(data);\n}\n\n";
   }
   else{
    $construc .= " $mem *the_$mem";
    unless(exists( $hash{ $mem} ))
     {
     $parser .= "void ${cname}::addNode($mem *the_$mem)\n{\n";
     $parser .= "\tAppendChild(*the_$mem);\n}\n\n";
     $hash{$mem} = 1;
    }    
   }
   if( $flag =~ /false/ ){
    $flag = "true";
   }
  }
  
 if($rootflag =~ /false/)
 {
  $parser .= "bool ${cname}::Validate() const\n{\n";
  $parser .= "\treturn ValidateDTD(dtdData);\n";
  $parser .= "}\n\n";
  $parser .= "${cname}::${cname}(const std::string& XMLFile):Node(XMLFile)\n{\n";
  $parser .= "}\n\n";
  $rootflag = "true";
 }
  
  
  $construc .= " ):Node()\n{\n";
  $construc .= "\tSetNodeName(\"${cname}\");\n";
  foreach $mem (@subclass){
   if(/#PCDATA/){
    $construc .= "\taddData(data);\n";
   }
   else{
    $construc .= "\tAppendChild(*the_$mem);\n";
   }
  }
  $construc .= "}\n\n";
 }

 push(@classes, $cname);
 $interfacefile{ $cname } = $cinterdef;
 $implementheaderfile{ $cname } = $cimpheader;
 $implementcppfile { $cname } = $cimpcpp;
 
# $constructors{ $name } = $construc;
# $parsersvec{ $name } = $parser;
 $headerlist{ $cname } = $headerfile;
 $classdeflist{ $cname } = $class_name;

sub ProcAttList {
 my($name, $attribs)=@_;
 my($attrib, $atype, $ctype, $condit, $options, $deft);
 my(@options);
 my($builder);
 my($elemtype, $arrlen, $subparse, $req);

 die "ATTLIST $name without ELEMENT\n" if(!defined($interfacefile{ $name }));

 # bin some whitespace
 $attribs =~ s/^\s*//;
 $attribs =~ s/\s*$//;

 while(1){
  if($attribs =~ /^(\w+)\s+(\w+)\s+\#(\w+)\s*(.*)/){  # basic; whatever type
   $attrib=$1;
   $atype=$2;
   $condit=$3;
   $attribs=$4;

   $interfacefile{ $name} .= "\t//Get/Set functions for attribute $attrib\n";
   $interfacefile{ $name} .= "\tvirtual std::string Get$attrib(void) = 0;\n";
   $interfacefile{ $name} .= "\tvirtual void Set$attrib( const std::string& value ) = 0;\n";
   
   $implementheaderfile{ $name} .= "\t//Get/Set functions for attribute $attrib\n";
   $implementheaderfile{ $name} .= "\tstd::string Get$attrib(void);\n";
   $implementheaderfile{ $name} .= "\tvoid Set$attrib( const std::string& value );\n";
   
   $implementcppfile{ $name} .= "//Get/Set functions for attribute $attrib\n";
   $implementcppfile{ $name} .= "std::string ${name}::Get$attrib(void)\n{\n\treturn m_node.GetAttribute(\"$attrib\");\n}\n\n";
   $implementcppfile{ $name} .= "void ${name}::Set$attrib( const std::string& value )\n{\n\tm_node.SetAttribute(\"$attrib\",value);\n}\n\n";
   
   $builder .= "void ${name}::Set$attrib( const std::string& value ){\n\tSetAttribute(\"$attrib\",value);\n}\n\n";

#   $attributparser{ $name } .= $builder;
  }
  else{
   last;
  }
 }
}


# dtd on command line
$flag = "false";
$dtdf = undef();
my($curdir) = `pwd`;
chomp($curdir);
my($outdir) = undef();

my($cppfilename) = "xml_nxl";

$count = @ARGV;
if($count == 1){
 if($ARGV[0] =~ m{\.dtd\z}i){
  $dtdf = $ARGV[0];
 }
 else{
  $flag = "true";
 }
}
elsif($count == 3){
 if($ARGV[0] =~ m{\A-o}i){
  $outdir = $ARGV[1];
  $dtdf = $ARGV[2];
 }
 else{
  $flag = "true";
 } 
}
else{
 $flag = "true";
}

die "Usage: dtd2cpp.pl [switches] <document>
    -o <directory>     Outputdir - specify output directory
    -h                 Help - Show Class Generator usage help\n" if ($flag =~ /true/);

if(defined($outdir)){
 die "the directory ${outdir} don't exist!!!\n" unless(-e ${outdir});
 if($outdir =~ m{\/\z}){
  mkdir "${outdir}/include", 0700;
  mkdir "${outdir}/src", 0700;
 }
 else{
  mkdir "${outdir}/include", 0700;
  mkdir "${outdir}/src", 0700;
 }
}
else{
 if($dtdf =~ /(.*)\/(.*)/){
  $outdir = $1;
  mkdir "${outdir}/include", 0700;
  mkdir "${outdir}/src", 0700;
 }
 else{
  $outdir = $curdir;
  mkdir "${outdir}/include", 0700;
  mkdir "${outdir}/src", 0700;
 }
}

# input filename
open(DTD, $dtdf) || die "can't read $dtdf: $!\n";
$dtd=join('', <DTD>);
close(DTD);

$namespacename = "NxconInterface";
@classes=();

%interfacefile=();
%implementheaderfile=();
%implementcppfile=();

#%constructors=();
#%attributparser=();
#%parsersvec=();
#%headerlist=();
%classdeflist=();


$rootflag = "false";

sub GenerateTargetFile{
 my($oriname)=@_;
 my($intername) = ();
 my($headername) = ();
 my($cppname) = ();

# here generate interface header file
 $intername = "I$oriname";
 open (${intername}, ">${intername}.h") || die "Can't write ${intername}.h: $!\n";
 print ${intername} "// this is generated code, do not edit\n";
 print ${intername} "#pragma once\n\n";
 print ${intername} "#include <string>\n\n";
# print ${name} "#include \"nxl_xml_node.h\"\n";
 print ${intername} $headerlist{ $oriname } if defined($headerlist{ $oriname });
 print ${intername} "namespace ${namespacename}\n{\n";
#debug output message
print "${intername}\n";
 print ${intername} "$classdeflist{ $oriname }\n" if defined($classdeflist{ $oriname });
 print ${intername} $interfacefile{ $oriname } . "};\n\n";
 print ${intername} "extern \"C\" ${intername}* ${intername}_CreateNewInstance(void);\n\n}\n";
 close(${intername});
 
# here generate implement header file
 $headername = "$oriname";
 open (${headername}, ">${headername}.h") || die "Can't write ${headername}.h: $!\n";
 print ${headername} "// this is generated code, do not edit\n";
 print ${headername} "#pragma once\n\n";
 print ${headername} "#include \"I${headername}.h\"\n";
 print ${headername} "#include \"nxl_xml_node.h\"\n";
 print ${headername} "namespace ${namespacename}\n{\n";
 print ${headername} $implementheaderfile{ $headername };
# print ${headername} "\nprivate:\n\tNode m_node;\n};\n\n}\n";
print ${headername} "\n\tNode m_node;\n};\n\n}\n";
 close(${headername});
 
 $cppname = $oriname;
# here generate implement cpp file 
 open (${cppname}, ">${cppname}.cpp") || die "Can't write ${cppname}.cpp: $!\n";
 print ${cppname} "// this is generated code, do not edit\n\n\n";
 print ${cppname} "#include \"${cppname}.h\"\n\n";
 print ${cppname} "namespace ${namespacename}\n{\n";
# print ${name} $constructors{ ${name} } ;
# print ${name} $parsersvec{ ${name} } ;
# print ${name} $attributparser{ ${name} } if(defined($attributparser{ ${name} }));
 print ${cppname} $implementcppfile{ ${cppname} };
 print ${cppname} "\nI${cppname}* I${cppname}_CreateNewInstance(void)\n{\n\treturn new ${cppname}();\n}\n";
 print ${cppname} "};\n";
 close(${cppname});
 use File::Copy ;
 use strict ;
 move("${curdir}/${intername}.h","${outdir}/include/${intername}.h")||warn "could not copy files :$!" ;
 move("${curdir}/${headername}.h","${outdir}/include/${headername}.h")||warn "could not copy files :$!" ;
 move("${curdir}/${cppname}.cpp","${outdir}/src/${cppname}.cpp")||warn "could not copy files :$!" ;
}
$tempdtd = $dtd;
$tempdtd =~ s/\r\n//g;
 
$dtd =~ s/\n/''/ge;

# run thru the DTD
while(1){
 $dtd =~ s/^(.*?)</</;
# $dtd =~ s/[*+?]//g;
 if($dtd =~ /^<(.*?)>(.*)$/){
  $elem=$1;
  $dtd=$2;
  if($elem =~ /^\!ELEMENT\s+(\w+)\s+(.*)/){
   print "==>ELEMENT $1,$2\n";
      ProcElement($1, $2);
  }
  elsif($elem =~ /^\!ATTLIST\s+(\w+)\s+(.*)/){
  # print "ATTLIST $1\n";
      ProcAttList($1, $2);
  }
  elsif($elem =~ /^\!\-\-.*\-\-$/){
  # print "comment\n";
  }
  else {
   print "1111111111111\n";
   warn "can't understand $elem\n";
  }
 }
 else{
  print "parser over\n" if defined($elem);
  last;
 }
}

# class declarations & code
for(@classes){
 GenerateTargetFile($_);
}

# generate Makefile file
open(MAKEFILE, ">Makefile") || die "Can't write Makefile: $!\n";
print MAKEFILE "#
# ! Don't modify this file
#   Modify Makefile.inc instead
#
ifeq (\$(NLBUILDROOT),)
  \$(error NLBUILDROOT undefined.)
endif

ifeq (\$(NLEXTERNALDIR),)
  \$(error NLEXTERNALDIR undefined.)
endif

#
#  Following master make file can be included:
#    - master.cxx.mak
#    - master.csharp.mak
#    - master.java.mak
#
\$(info Include master makefile: \$(NLBUILDROOT)/scripts/make/master.cxx.mak)
include \$(NLBUILDROOT)/scripts/make/master.cxx.mak
";
close(MAKEFILE);
move("${curdir}/Makefile","${outdir}/Makefile")||warn "could not copy files :$!" ;

# generate Makefile.inc file
open(MAKEFILEINC, ">Makefile.inc") || die "Can't write Makefile: $!\n";
print MAKEFILEINC
"
##############################################################################
#
#  The Makefile.inc will be used by master Makefile
#  under NLBUILDROOT/scripts/make directory.
#
##############################################################################

#
# The name of the target
#
TARGET_NAME=nxxmlconfig
\$(info Makefile.inc for project \$(TARGET_NAME))


#
#  VERSION
#
VERSION_PRODUCT  = \$(VERSION_PRODUCT_RMP)
VERSION_MAJOR  = \$(VERSION_MAJOR_RMP)
VERSION_MINOR  = \$(VERSION_MINOR_RMP)
VERSION_MAINTENANCE = \$(VERSION_MAINTENANCE_RMP)
VERSION_PATCH  = \$(VERSION_PATCH_RMP)

 

#
# The type of target, could be one of following values:
#   - exe:  An executable file
#   - lib:  A static library (user/kernel mode)
#   - dll:  A dynamic link library (user/kernel mode)
#   - sys:  A kernel driver
#
TARGET_TYPE=dll

#
#  The run mode of target
#   - kernel
#   - user
#
TARGET_MODE=user

#  Make sure the sys target run at kernel mode
ifeq (\$(TARGET_TYPE), sys)
  ifeq (\$(TARGET_MODE), user)
    \$(error A sys target must run at kernel mode.)
  endif
endif


#
#  Additional settings for EXE
#
ifeq (\$(TARGET_TYPE), exe)

  # Application type: CONSOLE or WIN32
  # console: this is a console application
  # win32:   this is a win32 application
  EXE_TYPE = console
 
  #
  #  Do we need to elevate privilege?
  #   - Invoke
  #   - Administrator
  #
  EXE_PRIVILEGE = Invoke
 
  #
  #  Is this a test app?
  #   - yes
  #   - no or empty
  #
  #EXE_TESTAPP = yes
 
endif

#
#  Source file
#
SRC = \\";
foreach (@classes){
 print MAKEFILEINC "
   src/$_.cpp \\"; 
}

print MAKEFILEINC "
      src/nxl_xml_node.cpp
   
 

#
#  Resource file
#  If this variable is empty, a default rc file will be used automatically
#
RCSRC =


#
#  Additional include directories
#
INCPATH += \\
    \$(NLEXTERNALDIR)/libxml2-2.7.8.win32/include \\
    \$(NLEXTERNALDIR)/libxml2-2.7.8.win32/include/libxml \\
    \$(NLEXTERNALDIR)/boost/boost_1_55_0 

#
#  Additional library directories
#
LIBPATH += \\
     \$(NLEXTERNALDIR)/libxml2-2.7.8.win32/lib \\
     \$(NLEXTERNALDIR)/boost/boost_1_55_0/libs/\$(BINDIR) \\
     \$(NLBUILDROOT)/bin/\$(BINDIR)


#
#  Additional librarys
#
LIBS += \\
  libxml2 

";
close(MAKEFILEINC);
move("${curdir}/Makefile.inc","${outdir}/Makefile.inc")||warn "could not copy files :$!" ;

# generate nxxmlconfig.def file
open(DEFFILE, ">nxxmlconfig.def") || die "Can't write nxxmlconfig.def: $!\n";
print DEFFILE "EXPORTS\n";
foreach $tem(@classes){
  print DEFFILE "\tI${tem}_CreateNewInstance\n";
}
close(DEFFILE);
move("${curdir}/nxxmlconfig.def","${outdir}/src/nxxmlconfig.def")||warn "could not copy files :$!" ;

# generate nxxmlconfig_helper.h file
open(HELPERFILE, ">nxxmlconfig_helper.h") || die "Can't write nxxmlconfig_helper.h: $!\n";
print HELPERFILE "#pragma once\n\n";
foreach (@classes){
 print HELPERFILE "#include \"I$_.h\"\n";
}
close(HELPERFILE);
move("${curdir}/nxxmlconfig_helper.h","${outdir}/include/nxxmlconfig_helper.h")||warn "could not copy files :$!" ;

#testtest only for test need, copy main.cpp nxl_xml_node.cpp nxl_xml_node.h
copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/nxl_xml_node.cpp","${outdir}/src/nxl_xml_node.cpp" ) || warn "could not copy files:$!";
copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/nxl_xml_node.h","${outdir}/include/nxl_xml_node.h" ) || warn "could not copy files:$!";
#testtest copy libxml dlls
unless ( -e "${outdir}/debug_win_x86" ){
 mkdir "${outdir}/debug_win_x86",0700;
}
copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/iconv.dll","${outdir}/debug_win_x86/iconv.dll" ) || warn "could not copy files:$!";
copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/zlib1.dll","${outdir}/debug_win_x86/zlib1.dll" ) || warn "could not copy files:$!";
copy("C:/Snow/Ruby/dev/ruby_starter_140507/common/libxml2.dll","${outdir}/debug_win_x86/libxml2.dll" ) || warn "could not copy files:$!";

 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值