Tuesday, December 30, 2008

systemverilog wordfile

copied from http://avm-users.googlegroups.com/web/systemverilog.txt?hl=en&gsc=Lb4u6AsAAADWzOiV2TvclJOPyNlia6Gs
/L20"Verilog 1364-2001" Line Comment = // Block Comment On = /* Block Comment Off = */ String Chars = " File Extensions = SV SVL/Delimiters = ~!@%^&*()-+=|\/{}[]:;"<> , .?#/Function String = "%[a-z0-9]+[ ^t]+[a-z_0-9]+[ ^t]+("
/Indent Strings = "begin" "fork" "specify" "config"
/Unindent Strings = "end" "join" "join_any" "join_none" "endspecify" "endconfig"
/C1"Keywords"
alias always always_comb always_ff always_latch and assert assign assume automatic 
before begin bind bins binsof bit break buf bufif0 bufif1 byte
case casex casez cell chandle class clocking cmos config const constraint context continue cover covergroup coverpoint cross
deassign default defparam design disable dist do
edge else end endcase endclass endclocking endconfig endfunction endgenerate endgroup endinterface endmodule endpackage endprimitive endprogram endproperty endspecify endsequence endtable endtask enum event expect export extends extern
final first_match for force foreach forever fork forkjoin function
generate genvar
highz0 highz1
if iff ifnone ignore_bins illegal_bins import incdir include initial inout input inside instance int integer interface intersect join
join_any join_none
large liblist library local localparam logic longint
macromodule matches medium modport module
nand negedge new nmos nor noshowcancelled not notif0 notif1 null
or output
package packed parameter pmos posedge primitive priority program property protected pull0 pull1 pulldown pullup pulsestyle_onevent pulsestyle_ondetect pure
rand randc randcase randsequence rcmos real realtime ref reg release repeat return rnmos rpmos rtran rtranif0 rtranif1
scalared sequence shortint shortreal showcancelled signed small solve specify specparam static string strong0 strong1 struct super supply0 supply1
table tagged task this throughout time timeprecision timeunit tran tranif0 tranif1 tri tri0 tri1 triand trior trireg type typedef
union unique unsigned use
var vectored virtual void
wait wait_order wand weak0 weak1 while wildcard wire with within wor
xnor xor
/C2"System"
** 'b 'B 'o 'O 'd 'D 'h 'H 'sb 'sB 'so 'sO 'sd 'sD 'sh 'sH 'Sb 'SB 'So 'SO 'Sd 'SD 'Sh 'SH
** _
$assertkill $assertoff $asserton $async$and$array $async$nand$array $async$or$array $async$nor$array $async$and$plane $async$nand$plane $async$or$plane $async$nor$plane
$bits $bitstoreal $bitstoshortreal 
$cast $comment $countdrivers $countones
$date $dimensions $display $displayb $displayh $displayo $dist_chi_square $dist_erlang $dist_exponential $dist_normal $dist_poisson $dist_t $dist_uniform $dumpall $dumpflush $dumpfile $dumplimit $dumpoff $dumpon $dumpports $dumpportsall $dumpportsflush $dumpportslimit $dumpportsoff $dumpportson $dumpvars
$enddefinitions $error $exit
$fatal $fdisplay $fdisplayf $fdisplayb $fdisplayh $fdisplayo $fell $feof $ferror $fflush $fgetc $fgets $finish $fopen $fmonitor $fmonitorb $fmonitorf $fmonitorh $fmonitoro $fclose $fread $fscanf $fseek $fsscanf $fstrobe $fstrobeb $fstrobef $fstrobeh $fstrobeo $ftell $fullskew $fwrite $fwriteb $fwritef $fwriteh $fwriteo 
$get_coverage $getpattern
$high $hold $history
$increment $incsave $info $input $isunbounded $isunknown $itor
$key 
$left $list $load_coverage_db $log $low 
$monitor $monitorb $monitorh $monitoro $monitoron $monitoroff 
$nochange $nokey $nolog $onehot $onehot0
$past $period $printtimescale
$q_add $q_exam $q_full $q_initialize $q_remove $q_random
$random $readmemb $readmemh $realtime $realtobits $recovery $recrem $removal $reset $reset_count $reset_value $restart $rewind $right $root $rose $rtoi
$sampled $save $scale $scope $sdf_annotate $set_coverage_db_name $setup $setuphold $sformat $shortrealtobits $showvariables $showscopes $showvars $signed $size $skew $sreadmemb $sreadmemh $sscanf $stable $stime $stop $strobe $strobeb $strobeh $strobeo $swrite $swriteb $swriteh $swriteo $sync$and$array $sync$nand$array $sync$or$array $sync$nor$array $sync$and$plane $sync$nand$plane $sync$or$plane $sync$nor$plane
$test$plusargs $time $timeformat $timescale $timeskew $typename $typeof
$ungetc $unit $unpacked_dimensions $unsigned $upscope $urandom $urandom_range
$value$plusargs $var $vcdclose $version
$warning $width $write $writeb $writeh $writeo $writememb $writememh

/C3"Operators"
->
+:
-:
@
@*
*>
,
;
.*
{
}
+
-
// /
*
**
%
>
>=
>>
>>>
<
<=
<<
<<<
!
!=
!==
&
&&
|
||
=
==
===
^
^~
~
~^
~&
~|
?
:
|->
|=>
/C4"Directives"
** `
`begin_keywords
`accelerate `autoexepand_vectornets
`celldefine
`default_nettype `define `default_decay_time `default_trieg_distributed `default_trireg_strength `delay_mode_distributed `delay_mode_path `delay_mode_unit `delay_mode_zero
`else `elsif `endcelldefine `endif `end_keywords `endprotect `endprotected `expand_vectornets
`file
`ifdef `ifndef `include
`line
`noaccelerate `noexpand_vectornets `noremove_gatenames `noremove_netnames `nounconnected_drive
`pragma `protect `protected
`remove_gatenames `remove_netnames `resetall
`timescale
`unconnected_drive `undef `uselib


/C5"DelaysAndParameters"
#
##

Make script

The oritinal page is http://www.hsrl.rutgers.edu/ug/make_help.html
How to write a Makefile

How to write a Makefile



Introduction


Make is one of the original Unix tools for Software Engineering. By
S.I. Feldman of AT&T Bell Labs circa 1975. But there are public
domain versions (eg. GNU) and versions for other systems
(eg. Vax/VMS).


Related tools are the language compilers (cc, f77, lex, yacc, etc.)
and shell programming tools (eg. awk, sed, cp, rm, etc.). You need to
know how to use these.


Important adjuncts are lint (source code checking for obvious errors)
ctags (locate functions, etc. in source code) and mkdepend. These are
nice, and good programmers use them.


Important, and related tools, are the software revision systems SCCS (Source Code Control System) and RCS (Revision Control System -- the recommended choice)

The idea is to automate and optimize the construction of
programs/files -- ie. to leave enough foot prints so that others can
follow.

Makefile Naming



make is going to look for a file called Makefile, if not found then a
file called makefile. Use the first (so the name stands out in
listings).


You can get away without any Makefile (but shouldn't)! Make has
default rules it knows about.

Makefile Components




  • Comments


    Comments are any text beginning with the pound (#) sign. A
    comment can start anywhere on a line and continue until the end of the
    line. For example:


    # $Id: slides,v 1.2 1992/02/14 21:00:58 reggers Exp $


  • Macros

    Make has a simple macro definition and substitution mechanism. Macros are defined in a Makefile as = pairs. For example:


    MACROS= -me
    PSROFF= groff -Tps
    DITROFF= groff -Tdvi
    CFLAGS= -O -systype bsd43

    There are lots of default macros -- you should honor the existing naming conventions. To find out what rules/macros make is using type:

    % make -p

    NOTE: That your environment variables are exported into the make as macros. They will override the defaults.


    You can set macros on the make command line:


    % make "CFLAGS= -O" "LDFLAGS=-s" printenv
    cc -O printenv.c -s -o printenv


  • Targets

    You make a particular target (eg. make all), in none specified then the first target found:


    paper.dvi: $(SRCS)
    $(DITROFF) $(MACROS) $(SRCS) >paper.dvi

    NOTE: The the line beginning with $(DITROFF) begins with TAB not spaces.

    The target is made if any of the dependent files have changed. The dependent files in this case are represented by the $(SRCS) statement.



  • Continuation of Lines

    Use a back slash (\). This is important for long macros and/or rules.




  • Conventional Macros


    There are lots of default macros (type "make -p" to print out the defaults). Most are pretty obvious from the rules in which they are used:


    AR = ar
    GFLAGS =
    GET = get
    ASFLAGS =
    MAS = mas
    AS = as
    FC = f77
    CFLAGS =
    CC = cc
    LDFLAGS =
    LD = ld
    LFLAGS =
    LEX = lex
    YFLAGS =
    YACC = yacc
    LOADLIBS =
    MAKE = make
    MAKEARGS = 'SHELL=/bin/sh'
    SHELL = /bin/sh
    MAKEFLAGS = b


  • Special Macros


    Before issuing any command in a target rule set there are certain special macros predefined.



    1. $@ is the name of the file to be made.
    2. $? is the names of the changed dependents.


    So, for example, we could use a rule


    printenv: printenv.c
    $(CC) $(CFLAGS) $? $(LDFLAGS) -o $@

    alternatively:

    printenv: printenv.c
    $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@

    There are two more special macros used in implicit rules. They are:


    1. $< the name of the related file that caused the action.
    2. $* the prefix shared by target and dependent files.



  • Makefile Target Rules


    The general syntax of a Makefile Target Rule is


    target [target...] : [dependent ....]
    [ command ...]

    Items in brackets are optional, ellipsis means one or more.
    Note the tab to preface each command is required.


    The semantics is pretty simple. When you say "make target"
    make finds the target rule that applies and, if any of the
    dependents are newer than the target, make executes the com-
    mands one at a time (after macro substitution). If any
    dependents have to be made, that happens first (so you have
    a recursion).


    A make will terminate if any command returns a failure sta-
    tus. That's why you see rules like:


    clean:
    -rm *.o *~ core paper

    Make ignores the returned status on command lines that begin
    with a dash. eg. who cares if there is no core file?


    Make will echo the commands, after macro substition to show
    you what's happening as it happens. Sometimes you might want
    to turn that off. For example:


    install:
    @echo You must be root to install



  • Example Target Rules


    For example, to manage sources stored within RCS (sometimes
    you'll need to "check out" a source file):


    SRCS=x.c y.c z.c

    $(SRCS):
    co $@

    To manage sources stored within SCCS (sometimes you'll need
    to "get" a source file):

    $(SRCS):
    sccs get $@

    Alternativley, to manage sources stored within SCCS or RCS
    let's generalize with a macro that we can set as required.

    SRCS=x.c y.c z.c
    # GET= sccs get
    GET= co

    $(SRCS):
    $(GET) $@

    For example, to construct a library of object files

    lib.a: x.o y.o z.o
    ar rvu lib.a x.o y.o z.o
    ranlib lib.a

    Alternatively, to be a bit more fancy you could use:

    OBJ=x.o y.o z.o
    AR=ar

    lib.a: $(OBJ)
    $(AR) rvu $@ $(OBJ)
    ranlib $@

    Since AR is a default macro already assigned to "ar" you can
    get away without defining it (but shouldn't).


    If you get used to using macros you'll be able to make a few
    rules that you can use over and over again.

    For example, to construct a library in some other directory


    INC=../misc
    OTHERS=../misc/lib.a

    $(OTHERS):
    cd $(INC); make lib.a

    Beware:, the following will not work (but you'd think it
    should)

    INC=../misc
    OTHERS=../misc/lib.a

    $(OTHERS):
    cd $(INC)
    make lib.a

    Each command in the target rule is executed in a separate
    shell. This makes for some interesting constructs and long
    continuation lines.


    To generate a tags file


    SRCS=x.c y.c z.c
    CTAGS=ctags -x >tags

    tags: $(SRCS)
    ${CTAGS} $(SRCS)

    On large projects a tags file, that lists all functions and
    their invocations is a handy tool.


    To generate a listing of likely bugs in your problems

    lint:
    lint $(CFLAGS) $(SRCS)

    Lint is a really good tool for finding those obvious
    bugs that slip into programs -- eg. type classes, bad argu-
    ment list, etc.


  • Some Basic Make Rule


    People have come to expect certain targets in Makefiles. You
    should always browse first, but it's reasonable to expect
    that the targets all (or just make), install, and clean will
    be found.



    1. make all -- should compile everything so that you can do local testing before installing things.
    2. make install -- should install things in the right places. But watch out that things are installed in the right place for your system.
    3. make clean -- should clean things up. Get rid of the executables, any temporary files, object files, etc.


    You may encounter other common targets, some have been
    already mentioned (tags and lint).



  • An Example Makefile for printenv



    # make the printenv command
    #
    OWNER=bin
    GROUP=bin
    CTAGS= ctags -x >tags
    CFLAGS= -O
    LDFLAGS= -s
    CC=cc
    GET=co
    SRCS=printenv.c
    OBJS=printenv.o
    SHAR=shar
    MANDIR=/usr/man/manl/printenv.l
    BINDIR=/usr/local/bin
    DEPEND= makedepend $(CFLAGS)
    all: printenv

    # To get things out of the revision control system
    $(SRCS):
    $(GET) $@
    # To make an object from source
    $(CC) $(CFLAGS) -c $*.c

    # To make an executable

    printenv: $(OBJS)
    $(CC) $(LDFLAGS) -o $@ $(OBJS)

    # To install things in the right place
    install: printenv printenv.man
    $(INSTALL) -c -o $(OWNER) -g $(GROUP) -m 755 printenv $(BINDIR)
    $(INSTALL) -c -o $(OWNER) -g $(GROUP) -m 644 printenv.man $(MANDIR)

    # where are functions/procedures?
    tags: $(SRCS)
    $(CTAGS) $(SRCS)

    # what have I done wrong?
    lint: $(SRCS)
    lint $(CFLAGS) $(SRCS)

    # what are the source dependencies
    depend: $(SRCS)
    $(DEPEND) $(SRCS)

    # to make a shar distribution
    shar: clean
    $(SHAR) README Makefile printenv.man $(SRCS) >shar

    # clean out the dross
    clean:
    -rm printenv *~ *.o *.bak core tags shar

    # DO NOT DELETE THIS LINE -- make depend depends on it.
    printenv.o: /usr/include/stdio.h




  • Makefile Implicit Rules


    Consider the rule we used for printenv


    printenv: printenv.c
    $(CC) $(CFLAGS) printenv.c $(LDFLAGS) -o printenv

    We generalized a bit to get

    printenv: printenv.c
    $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@

    The command is one that ought to work in all cases where we
    build an executable x out of the source code x.c This can be
    stated as an implicit rule:

    .c:
    $(CC) $(CFLAGS) $@.c $(LDFLAGS) -o $@

    This Implicit rule says how to make x out of x.c -- run cc
    on x.c and call the output x. The rule is implicit because
    no particular target is mentioned. It can be used in all
    cases.


    Another common implicit rule is for the construction of .o
    (object) files out of .c (source files).


    .o.c:
    $(CC) $(CFLAGS) -c $<

    alternatively

    .o.c:
    $(CC) $(CFLAGS) -c $*.c


  • Make Dependencies


    It's pretty common to have source code that uses include
    files. For example:


    % cat program.c

    #include
    #include "defs.h"
    #include "glob.h"
    etc....
    main(argc,argv)
    etc...

    The implicit rule only covers part of the source code depen-
    dency (it only knows that program.o depends on program.c).
    The usual method for handling this is to list the dependen-
    cies separately;

    etc...
    $(CC) $(CFLAGS) -c $*.c
    etc...
    program.o: program.c defs.h glob.h

    Usually an implicit rule and a separate list of dependencies
    is all you need. And it ought to be easy enough to figure
    out what the dependencies are.


    However, there are a number of nice tools around that will
    automatically generate dependency lists for you. For example
    (trivial):


    DEPEND= makedepend $(CFLAGS)
    etc...
    # what are the source dependencies

    depend: $(SRCS)
    $(DEPEND) $(SRCS)

    etc....
    # DO NOT DELETE THIS LINE -- ....

    printenv.o: /usr/include/stdio.h

    These tools (mkdepend, mkmkf, etc.) are very common these
    days and aren't too difficult to use or understand. They're
    just shell scripts that run cpp (or cc -M, or etc.) to find
    out what all the include dependencies are. They then just
    tack the dependency list onto the end of the Makefile.



Based on Make and Makefiles by
Reg Quinton

Computing and Communications Services

The University of Western Ontario

London, Ontario N6A 5B7

Canada




Press here to return to the General Unix Software Menu.

System Verilog by example by example

System Verilog by example(constraint, random, covergroup)
module top;
typedef enum bit { BAD_PARITY, GOOD_PARITY } parity_e;
class packet_c;
rand bit [5:0] pkt_length;
bit[63:0][7:0] pkt_payload;
bit[7:0] parity;
rand parity_e parity_type;
function bit [7:0] calc_parity();
 calc_parity = { pkt_length, pkt_addr };
 for (int i = 0; i calc_parity ^= pkt_payload[i];
endfunction :calc_parity

function void randomize_payload();
 pkt_addr = $urandom ;
 pkt_length = $urandom ;
 for (int i=0; i < pkt_length; i ++)
  pkt_payload[i]= $urandom;
endfunction:randomize_payload

function void post_randomize();
  randomize_payload();  
  if (parity_type == GOOD_PARITY)
  parity = calc_parity();
  else
  do
  parity = $urandom;
  while (parity == calc_parity());
endfunction:post_randomize

endmodule

class packet_c;
typedef enum bit { BAD_PARITY , GOOD_PARITY } parity_e;
typedef enum bit[1:0] { SMALL,MEDIUM, LARGE } payload_e;
  constraint c { parity_type == GOOD_PARITY ;}
  constraint c1 { payload_type == LARGE ;}
  constraint c3 { pkt_addr == 2; }
  constraint length_range {
  (payload_type == SMALL) -> pkt_length inside { [1 : 20] };
  (payload_type == MEDIUM) -> pkt_length inside { [21 : 44]};
  (payload_type == LARGE) -> pkt_length inside { [45 : 63]};
  }
// Define the Coverage module for the packet defined
  covergroup cg @ (pkt_event);
  coverpoint pkt_length {
  bins usb_range = {[0 : 20]};
  bins pci_range = {[21 : 44]};
  bins ahb_range = {[45 : 63 ]};
  }
  coverpoint pkt_addr;
  coverpoint parity;
  endgroup


Monday, December 1, 2008

水仙养殖

宝贝名称:水仙种球(别名:凌波仙子、玉玲珑、金盏银台等)

宝贝特点:为石蒜科多年生草本。地下部分的鳞茎肥大似洋葱,卵形至广卵状球形,外被棕褐色皮膜。叶狭长带状,二列状着生。花葶中空,扁筒状,通常每球有花葶数支,多者可达10余支,每葶数支,至10余朵,组成伞房花序。

栽培方法:栽培水仙有水培法和土培法两种方法。

一:水培法:即用浅盆水浸法培养。将水仙直立放入水仙浅盆中,加水淹没鳞茎三分之一的为宜。盆中可用石英砂 、鹅卵石等将鳞茎固定。

阳光:白天要放置在阳光充足的地方,夜晚可放在灯光下;

温度:以10-15度为宜,过低(4度以下)容易发生冻害,过高(20度以上)容易发生徒长;

换水:刚上盆时,水仙可每日换一次水,以后每2-3天换一次,花苞形成后,每周换一次水。为防止叶片徒长,最好是傍晚把盆水倒尽,次日清晨再加清水;

花期调控:一般水仙从上盆到开花约45天,但通过适当调控,可以在28天内至60天左右开花,比如节前10天还未看到饱满花苞,可改用接近体温的温水浸泡,并适当添加营养液催花;若想延长开花时间,则可将水仙放至温度较低处4-5度,适当控水等; 

按照以上方法,可使水仙叶短宽厚、茁壮,叶色浓绿,花开香浓。水养水仙,一般不需要施肥,如有条件,在开花期间稍施一些速效磷肥,花可开得更好。

二:土培法:准备肥沃的沙质土壤,将水仙种球栽入一半露出一半,鳞下面应事先垫一些细沙,以利排水。把花盆置于阳光充足、温度适宜的室内。以4至12℃为好,温度过低容易发生冻害,温度过高再加之光照不足,容易陡长,植株细弱,开花时间短暂,降低观赏价值。管理中如果满足光照和温度的要求,则叶片肥大,花莛粗壮,因而能使花朵开得大,芳香持久。土培水仙,可在开花前追施二至三次液肥。

Sunday, November 30, 2008

cadence eplanner/emanager

NTF
Nested Text Format (NTF) is a standard format for defining a nested list of containers that hold attribute/value pairs. The following files used by Enterprise Manager conform to this format:
• vplan
• vsif
• vsof
• config
• views
• coverage_attributes
• instance_map

NTF is a meta format, like XML. Specific files are not in NTF format, but in some descendant format.

The BNF description of the NTF format is:
entity_list : entity entity_list entity
entity : container attribute ’;’ ’;’
container : container_type BLANK container_name ’{’ entity_list ’}’
container_type : IDENTIFIER
container_name : IDENTIFIER NON_RESERVED_CHARACTER_TOKEN STRING
attribute : attribute_name ’:’ attribute_value
attribute_name : IDENTIFIER
attribute_value : TEXT STRING data
data : NON_RESERVED_CHARACTER_TOKEN
data BLANK NON_RESERVED_CHARACTER_TOKEN
IDENTIFIER : [_a-zA-Z][0-9_a-zA-Z]*
STRING ’[^’\n]*’ "[^"\n]*"
TEXT .*
BLANK [ \n\t\r]+
NON_RESERVED_CHARACTER_TOKEN [^ \n\;:{}’"]+


The container identifier is dependent on file type. For example:
vsif files session, group or test
vsof files session_output, run, failure, coverage_model, coverage_data
vplan files import, section, perspective, coverage, extend, instantiate or within.


Identifiers are case insensitive.

You can add #include directives anywhere in the NTF file.

The following containers are valid within a vplan file:
import {}: Import an XML plan into an NTF plan
import DMA_Verif_Plan {
vplan_file_name: "/vobs/plans/DMA_Verif_plan.xml"
};
section{}:Define hierarchy in a verification plan model
section Xbus_subsystem {
section Reading_from_Xcore {
coverage: vr_xbus_master_sequence.read_ended;
};
section Writing_to_Xcore {
coverage: vr_xbus_master_sequence.write_ended;
};
};
perspective{}:Defines attributes for a subset of the verification plan sections
Syntax Example
perspective Integration {
top_section: Full_SoC;
};
perspective Prototype {
top_section: Xbus_subsystem;
};
perspective Production {
top_section: Xserial_subsystem;
};
coverage{}:Define a coverage group, while allowing filtering and weighting
coverage valid_small_packets {
items_pattern: packet.gen.cross_all;
buckets_filter : len <>UCM
a coverage model is a hierarchical list of all the checks and coverage points in the DUT that you want to monitor during the run.
Incisive Simulator and Specman generate separate coverage model files.
Incisive Simulator writes the coverage model during the first run on a design. For subsequent runs on the same design, Incisive Simulator does not write the coverage model unless some special occasions
When Specman is run under Enterprise Manager, the coverage model format is set automatically to ucm, the Unicov format that Enterprise Manager requires.

By default, the HDL coverage model is written to:
/model_dir/_.ucm
To specify the location of the HDL model file, use the cov options to irun or ncsim. For example, with the following settings:
-covworkdir $DIR(session)
-covdesign $ENV(MY_DESIGN)
-covtest $BRUN_RUN_ID
The HDL coverage model is written to the following directory:
$BRUN_SESSION_DIR/model_dir/$MY_DESIGN/$BRUN_RUN_ID.ucm

VSIF
A verification session input format (vsif) file specifies one or more tests to be run in a single session.
The individual tests and the session itself have multiple attributes, including the testbench top files, the seed, and the SVE.
you can used any standard CPPdirective, including #define, #ifdef, and #ifndef.
There are three types of top-level containers in a vsif file:
•The session container describes default session attributes that apply globally to all tests.
•The optional group container holds one or more test containers and describes default test attributes that apply to all tests contained within it.
•The test container describes the attributes of a specific test, including, for example, the seed and the number of times the test must be run.
The following is a simple vsif, specifying one test to be run five times (count: 5 is specified) with
random seeds (there is no seed: n specified):
session short_tests {
top_dir : $VM_WORK/vm_xsoc;
pre_session_script: vm_xsoc/scripts/setup_xsoc.sh;
};
group xsoc_tests {
run_script: vm_xsoc/scripts/run_ex_vm_xsoc.sh;
scan_script: "vm_scan.pl ies.flt shell.flt";
timeout : 300;
pre_commands: "set checks ERROR_CONTINUE";
test test_simple {seed: 1;top_files: "vm_xsoc/examples/test_simple.e";};
test input_from_xbus {top_files: "vm_xsoc/examples/input_from_xbus.e";};
};
test simple_test {
run_script: vm_xsoc/scripts/run_ex_vm_xsoc.sh;
scan_script: "vm_scan.pl ius.flt shell.flt";
count: 5;
};

coverage

cited from http://www.ovmworld.org/forums/showthread.php?t=121
Code coverage: This will give information about how many lines are exected, how many times expressions, branches executed. This coverage is collected by the simulation tools. Users use this coverage to reach those corner cases which are not hit by the random testcases. Users have to write the directed testcases to reach the missing code covearage areas.

Functional coverage: This coverage will be defined by the user. User will define the coverage points for the functions to be covered in DUT. This is completly under user control. like covergroup definition defined in SV

Both of them have equal importance in the verification. 100% functional coverage does not mean that the DUT is completly exercised and vice-versa. Verification engineers will consider both coverages to measure the verifcation progress.

Coverage tool
All the HVL simulators have Functional Coverage tool with it.You have to write coverage code and then switch ON the coverage during simulation.
And use a coverage viewing tool (again, the same EDA company will have it) to view the coverage.
For Cadence IES/IUS:
1. For switching coverage ON:Use +nccovfile+dut_cov.txt while compiling.
The content of dut_cov.txt is:
select_coverage -all -module top
...
select_functional
select_fsm
During simulation use:-covoverwrite -covtest mycov.cov
2. To view coverage:
Do:
iccr -keywords+detail iccr.cmd
or:
iccr -keywords+summary iccr.cmd
or:
iccr -keywords+dontmerge iccr.cmd
The respective content of iccr.cmd is:
load_test cov_work/design/*merge * -output ALL
reset_coverage
load_test cov_work/design/ALL
report_detail -instance -betsafd -cgopt top... > detail.rpt

load_test cov_work/design/*merge * -output ALL
reset_coverage
load_test cov_work/design/ALL
report_summary -instance -cgopt top... > summary.rpt

load_test cov_work/design/*
report_summary -instance -cgopt top... > summary.rpt

There is a coverage quick start guide included with IUS as well in order to get you started. Search for "icc quick start guide" in cdnshelp

Wednesday, November 19, 2008

签证

申根签证 (摘自百度,http://baike.baidu.com/view/639689.htm)

1.渊源

申根(Schengen)是卢森堡东南端一个人口不足450人的宁静小城。

1985年有德国、法国、比利时、荷兰、卢森堡五国在这里共同签署了“关于逐步取消边界检查的条约”。加入条约的国家即简称为申根国家,取得申根国家的签证就是申根签证。

在这条约中明确规定:成员国中的公民可以任意出入成员国的国境而不需要办理签证手续,成员国以外的外籍人士,只要取得了成员国中一个国家的签证,便可在签证有效期内自由出入各成员国国境,而不需要再办签证,也可以在任何一个申根国家入境通行。乘坐申根国家之间的飞机航班就像乘国内航班一样,无需办理出入境手续。
从2007年12月21日起,《申根协定》参与国的范围将由目前的15国扩大到24国,匈牙利、捷克、斯洛伐克、斯洛文尼亚、波兰、爱沙尼亚、拉脱维亚、立陶宛和马耳他9个2004年才加入欧盟的国家也将成为申根大家庭中的成员。《申根协定》的“边界”将再一次得到拓展。

2.分类和申请申根签证的种类及申办办法:
  1)入境签证有一次入境和多次入境两种。签证持有者分别可一次连续停留90天或每半年多次累计不超过3个月。如需长期停留,可向某一成员国申请只在该使用的国别签证;
  2)过境签证指过境前往协定国以外国家的签证.一般有一次、两次两种、特殊情况下可颁发多次过境签。每次过境时间一般为3天,最长为5天

只前往某一成员国,应申办该国的签证,即“国别签证”。“国别签证”只能入、出签发国有效,不能从别的申根国家过境而进入签发国,否则应申办“申根签证”。签证上的停留天数只在签证有效期内停留有效;只办一次入境有效的“申根签证”,只能在有效期内在申根国家区域内旅行,不能中途转机去非申根国家后又返回申根国家

个人怎样办理申根签证?

第一步:准备好8项相关资料
1申根国家的邀请函
2有效期六个月以上的个人护照
3护照照片10张
4申请人的身份证、户口本复印件
5所在单位的营业执照复印件及本人名片2张
6个人存款证明
7家庭地址及联系电话
8所在单位的担保信,中英文各一份。
第二步:去相关国家的驻华使馆办理
准备好相关资料后,需要去相关国家的驻华使馆办理。一次去若干国家的,通常向第一个抵达的国家或停留最长时间的国家大使馆办理。(来源:北京娱乐信报)


申根协定还包含以下原则:
1、申根协议国家应在人员流动方面,尤其是在签证方面采取统一的政策规定;
2、申根协议国家决定颁发在申根区域内普遍有效的统一签证;
3、允许一次或二次入境的短期旅行签证,其前提条件是逗留的天数总和在第一次入境后半年内不能超过3个月;
4、在申根签证使用前,各个国家的国别签证应该得到承认;
5、根据申根协议的规定,持有任何一个申根协议成员国有效居留许可证的旅行者,3个月内无需签证可在申根区域内自由旅行。在申根区域外的旅行者,只要持有某申根国家有效的居留许可证和护照,无需办理签证即可前往该申根国家。超过90天的逗留,申请者应根据有关法律及其逗留目的申请国别签证;
6、统一的申根签证应由协议国家的外交和领事部门颁发;
7、原则上说,颁发某申根签证的国家应该是该签证持有者的主要目的地国家,或者是该签证持有者进入的第一个申根国家;
8、旅行证件的有效期必须长于签证的有效期,该旅行证件必须保证申根国家以外的外国人能够顺利回到自己的国家或进入申根区域外的国家;
9、每个国家都有权决定某人是否有权进入该国,或被拒绝入境,他国颁发的申根签证在另一申根国家使用时将得到限制,但该国必须将有关情况通报其他协议国家;

DDR description

pins descriptions
A13,A12-A0:
Address inputs: Provide the row address for ACTIVATE commands,
and the column address and auto precharge bit (A10) for
READ/WRITE commands, to select one location out of the memory
array in the respective bank. A10 sampled during a PRECHARGE
command determines whether the PRECHARGE applies to one
bank (A10 LOW, bank selected by BA[2:0] or all banks (A10 HIGH).
The address inputs also provide the op-code during a LOAD MODE
command.
A13,A12-A0
Address inputs: Provide the row address for ACTIVATE commands,
and the column address and auto precharge bit (A10) for
READ/WRITE commands, to select one location out of the memory
array in the respective bank. A10 sampled during a PRECHARGE
command determines whether the PRECHARGE applies to one
bank (A10 LOW, bank selected by BA[2:0] or all banks (A10 HIGH).

BA0–BA2
Bank address inputs: BA[2:0] define to which bank an ACTIVATE,
READ, WRITE, or PRECHARGE command is being applied. BA[2:0]
define which mode register, including MR, EMR, EMR(2), and
EMR(3), is loaded during the LOAD MODE command.

CK, CK#
Clock: CK and CK# are differential clock inputs. All address and control
input signals are sampled on the crossing of the positive edge
of CK and negative edge of CK#. Output data (DQ and DQS/DQS#)
is referenced to the crossings of CK and CK#.

CKE
Clock enable: CKE (registered HIGH) activates

CS#
Chip select: CS# enables (registered LOW) and disables (registered
HIGH) the command decoder.

RAS#, CAS#,WE#
Command inputs: RAS#, CAS#, and WE# (along with CS#) define
the command being entered.

command
LOAD MODE (LM)
The mode registers are loaded via bank address and address inputs. The bank address
balls determine which mode register will be programmed.
RAS#/CAS#/WE#: L L L

ACTIVATE
The ACTIVATE command is used to open (or activate) a row in a particular bank for a
subsequent access. The value on the bank address inputs determines the bank, and the
address inputs select the row. This row remains active (or open) for accesses until a precharge
command is issued to that bank. A precharge command must be issued before
opening a different row in the same bank.
RAS#/CAS#/WE#: L H H

READ
The READ command is used to initiate a burst read access to an active row. The value
on the bank address inputs determine the bank, and the address provided on address
inputs A0–Ai (where Ai is the most significant column address bit for a given configuration)
selects the starting column location. The value on input A10 determines whether
or not auto precharge is used.
RAS#/CAS#/WE#: H L H

WRITE
The WRITE command is used to initiate a burst write access to an active row. The value
on the bank select inputs selects the bank, and the address provided on inputs A0–Ai
(where Ai is the most significant column address bit for a given configuration) selects
the starting column location. The value on input A10 determines whether or not auto
precharge is used.
RAS#/CAS#/WE#: H L L

PRECHARGE
The PRECHARGE command is used to deactivate the open row in a particular bank or
the open row in all banks.
RAS#/CAS#/WE#: L H L

REFRESH
REFRESH is used during normal operation of the DDR2 SDRAM and is analogous to CAS#-
before-RAS# (CBR) REFRESH.
RAS#/CAS#/WE#: L L H
CKE: previous H, now H

SELF REFRESH
The SELF REFRESH command can be used to retain data in the DDR2 SDRAM, even if
the rest of the system is powered down.
RAS#/CAS#/WE#: L L H
CKE: previous H, now L

Mode Register (MR)
The mode register is used to define the specific mode of operation of the DDR2 SDRAM.
This definition includes the selection of a burst length, burst type, CAS latency, operating
mode, DLL RESET, write recovery, and power-down mode,
1.Burst length is defined by bits M0–M2,
The block is uniquely selected by A2–Ai when BL = 4 and by A3–Ai when BL = 8. The remaining (least significant) address bit(s) is (are) used to select the starting location within the block.
2.Accesses within a given burst may be programmed to be either sequential or interleaved.
The burst type is selected via bit M3. sequential: use WRAP, and interleaved: grouped by 2
3.The normal operating mode is selected by issuing a command with bit M7 set to “0”. if 1, test mode and unpredicatable
4. DLL RESET is defined by bit M8, as shown in Figure 34 (page 77). Programming bit M8
to “1” will activate the DLL RESET function.
5. Write recovery (WR) time is defined by bits M9–M11.
6. Active power-down (PD) mode is defined by bit M12, which determines performance versus power savings.
7. The CAS latency (CL) is defined by bits M4–M6, as shown in Figure 34 (page 77). CL is
the delay, in clock cycles, between the registration of a READ command and the availability
of the first bit of output data. The CL can be set to 3, 4, 5, 6, or 7 clocks, depending
on the speed grade option being used.
Extended Mode Register (EMR)
The extended mode register controls functions beyond those controlled by the mode
register; these additional functions are DLL enable/disable, output drive strength, ondie
termination (ODT), posted AL, off-chip driver impedance calibration (OCD), DQS#
enable/disable, RDQS/RDQS# enable/disable, and output disable/enable.
Posted CAS additive latency (AL) is supported to make the command and data bus efficient
for sustainable bandwidths in DDR2 SDRAM. Bits E3–E5 define the value of AL,


Graphs

Ball



DDR RAM State Machine



Hierarchical Diagram



Read Timing diagram



Write Timing diagram


Typical AC/DC characteristics
tCK: 1.875~5 ns
CL: 7~3 tCK
TR and CP must have a minimum 500mV peak-to-peak swing.
Supply voltage Vdd: min 1.7, max 1.9 V
DC differential input voltage Vid(DC): min 250, max VddQ (mV)
Input high (logic 1) voltage: min Vih(DC), max Vref(DC) + 125 VddQ1 (mV)

led vs ccfl

。在视频领域,人们一般用NTSC作为衡量视频设备的色彩还原特性的标准。这个指标是指在整个色彩空间内,显示设备能在各种色彩上显示到何种饱和度,就是能够显示显眼到什么程度的蓝色、绿色、红色。对于传统的液晶电视和显示器而言,能够覆盖的色域范围只有NTSC标准的65%~75%。如果我们仔细观察其色域曲线,就会发现在绿色、黄色和红色部分和标准距离较远。因此,传统液晶电视的色彩范围较小,难以完美呈现绿草、大海等自然场景。


我们知道,液晶显示器本身不会发光,它依靠背光源将光线穿过显示面板,展现图形图像。因此,背光源的技术直接影响到液晶电视的画质。传统的液晶显示器通常采用冷阴极荧光灯(cold cathode fluorescent lamps,CCFL)作为光源,而正是CCFL造成了液晶显示器颜色不够丰富,色彩还原度差。我们再看Sony QUALIA005系列电视机,它把液晶电视的色域范围扩展到NTSC标准的105%,基本上可以重现我们所有观察到的自然界场景。其核心就是使用LED背光源替代传统的CCFL背光源。


LED背光技术领先优势

LED作为LCD的背光源,与传统背光技术相比,除了在色域范围的优势外,还有很多独特的优点,归纳为十个方面:

1)LED背光源有更好的色域。其色彩表现力强于CCFL背光源,可对显示色彩数量不足的液晶技术起到很好的弥补作用,色彩还原好;

2)LED的使用寿命可长达10万小时。即使每天连续使用10个小时,也可以连续用上27年,大大延长了液晶电视的使用寿命,可获得对等离子技术压倒性的优势;

3)亮度调整范围大。实现LED功率控制很容易,不像CCFL的最低亮度存在一个门槛。因此,无论在明亮的户外还是全黑的室内,用户都很容易把显示设备的亮度调整到最悦目的状态;

4)完美的运动图像。传统CCFL灯管的闪烁发光频率较低,表现动态场景可能产生画面跳动。LED背光可以灵活调整发光频率,而且频率大大高于CCFL,因此能完美地呈现运动画面;

5)实时色彩管理。由于红绿蓝3色独立发光,很容易精确控制目前的显示色彩特性;

6)可以调整的背光白平衡,同时保证整体对比度。当用户的视频源在计算机和DVD机间切换时,可以轻松在9600K和6500K间调整白平衡,而且不会牺牲亮度和对比度;

7)可以为大尺寸屏幕提供连续面阵光源。LED是一种平面状光源,最基本的发光单元是3~5mm边长的正方形封装后,极容易组合在一起成为既定面积的面光源,具有很好的亮度均匀性,如果作为液晶电视的背光源,所需的辅助光学组件可以做得非常简单,屏幕亮度均匀性更为出色;

8)安全。LED使用的是5~24V的低压电源,十分安全,供电模块的设计也颇为简单;

9)环保。LED光源没有任何射线产生,也没有水银之类的有毒物质,可谓是绿色环保光源;

10)抗震。平面状结构让LED拥有稳固的内部结构,抗震性能很出色。


表1、LED与CCFL对比
CCFL LED
色域 72% 105%
色温 固定 可变
频闪驱动 需要 不需要
上升/下降沿时间 500毫秒 20纳秒
寿命 5万小时 10万小时
功耗 110瓦 415瓦
厚度 32.5毫米 45毫米
灯/LED数量 16 455

(数据来源 :Samsung Electronics)

在液晶显示器已经成为主流显示器的今天,LED背光源凭借其独特、压倒性的优势,逐渐显示出强大的应用前景。



LED背光源现在存在的问题

LED背光技术就象许多新型技术一样拥有许多诱人的优点,但LED要想占据大尺寸LCD背光源的主流,目前还需要解决一些技术难点。通过表1的对比,我们已经发现LED在功耗方面处于劣势,除此之外还存在成本高、一致性差等问题。

1)LED的发光效率较低,与同等尺寸CCFL背光源相比耗电量高。目前CCFL的输出光通量多在5000~7000lm范围,实际屏幕的输出光通量高于300lm,而多数LED背光都还无法达到这一指标。不过,现在全球有大量的企业从事相关研究,LED发光效率提升相当之快,目前光通量达到10000lm 的高亮型LED背光也已经出现,相信离成熟仅是咫尺之遥。

2)成本太高、价格昂贵,同等尺寸的背光源,LED是CCFL价格的4倍。对于目前价格竞争激烈的市场而言,让厂家有些望而却步。只有索尼为了图像质量不计成本。当然,随着工艺的成熟和生产规模的增加,LED背光的成本会逐步下降。

3)用LED作为背光源存在白光的一致性问题,这比起CCFL是个劣势。

4)LED在网点设计上较线性光源CCFL难,需考虑LED辐射状的光强衰减。

5)RGB LED背光源时间一久会产生色移波长会随温度变化,产生不同颜色。

Tuesday, November 18, 2008

systemverilog keywords supported by synplify

Supported SystemVerilog Keywords:

always_comb, always_ff, always_latch, assert, bit byte, const, do, endinterface, enum, import, int, interface, logic, longint, modport, packed, priority, shortint, struct, typedef, unique.



Unsupported SystemVerilog Keywords:

assume, break, continue, endproperty, endsequence, expect, property, return, sequence, timeprecision, timeunit, union, void.

Friday, November 14, 2008

sdc cmd

Synopsys Design Constraint (SDC)

Synopsys Design Constraints (SDC) is a format used to specify the design intent, including the timing and area constraints for a design. SDC is based on the tool command language (Tcl). The Synopsys Design Compiler and PrimeTime tools use the SDC description to synthesize and analyze a design. In addition, these tools can generate SDC descriptions for and read SDC descriptions from thirdparty tools.

file format

SDC is a Tcl-based format. All commands in an SDC file conform to the Tcl syntax rules.
You use an SDC file to communicate the design intent, including timing and area requirements between EDA tools. An SDC file contains the following information:
• The SDC version (optional)
• The design constraints
• Comments (optional)

Limitations(?):Constraints imported from one SDC file will be discarded if a second SDC file is imported. All constraints must be imported from a single SDC file.

file version

set sdc_version value
If the SDC file does not specify a version, the Synopsys tools assume that the file uses version 1.4

SDC Constraint Commands

Type of information Commands
Operating conditions 
  set_operating_conditions
Wire load models 
  set_wire_load_min_block_size
  set_wire_load_mode
  set_wire_load_model
  set_wire_load_selection_group
System interface 
  set_drive
  set_driving_cell
  set_fanout_load
  set_input_transition
  set_load
  set_port_fanout_number
Design rule constraints 
  set_max_capacitance
  set_max_fanout
  set_max_transition
  set_min_capacitance
Timing constraints 
  create_clock
  create_generated_clock
  set_clock_gating_check
  set_clock_latency
  set_clock_transition
  set_clock_uncertainty
  set_data_check
  set_disable_timing
  set_input_delay
  set_max_time_borrow
  set_output_delay
  set_propagated_clock
  set_resistance
Timing exceptions
  set_false_path
  set_max_delay
  set_min_delay
  set_multicycle_path
Area constraints
  set_max_area
Power constraints
  set_max_dynamic_power
  set_max_leakage_power
Porosity constraints
  set_min_porosity
Logic assignments
  set_case_analysis
  set_logic_dc
  set_logic_one
  set_logic_zero
SDC Design Objects
Design object Access command Description
design
 current_design A container for cells. A block.
clock1
 get_clocks A clock in a design.
 all_clocks All clocks in a design.

port
 get_ports An entry point to or exit point from a design.
 all_inputs All entry points to a design.  
 all_outputs All exit points from a design.  

cell
 get_cells An instance of a design or library cell.
pin
 get_pins An instance of a design port or library cell pin.
net
 get_nets A connection between cell pins and design ports.
library
 get_libs A container for library cells.
lib_cell
 get_lib_cells A primitive logic element.
lib_pin
 get_lib_pins An entry point to or exit point from a lib_cell.

Validating SDC Files
To validate the syntax of an SDC file, use the read_sdc -syntax_only command in either Design Compiler or PrimeTime. The read_sdc -syntax_only command generates warning
messages if your SDC file contains unsupported commands or arguments.

Clock Constraint

create_clock -period period_value [-name clock_name] [-waveform edge_list] [port_pin_list]

period_value (specified in ns) is mandatory. There will be no clock created if the period is not supplied.
clock_name is optional. It is unnecessary if port_pin_list contains one name. edge_list is optional

port_pin_list may contain either zero names or one name

Max Delay Constraint
The set_max_delay constraint sets the path delay of the specified ports to a restricted value. The syntax is as follows:
set_max_delay [-from from_list] [-to to_list]
delay_value
• from_list is mandatory
• to_list is mandatory
• delay_value is specified in ns

Wednesday, November 12, 2008

systemverilog/ovm training


OVM overview
Data items represent the input to the DUT. Examples include networking packets, bus transactions, andinstructions
Driver(BFM): A driver is an active entity that emulates logic that drives the DUT. A typical driver repeatedly receivesa data item and drives it to the DUT by sampling and driving the DUT signals.
A sequencer is an advanced stimulus generator that controls the items that are provided to the driverfor execution.
A monitor is a passive entity that samples DUT signals but does not drive them. Monitors collectcoverage information and perform checking.
Agent: Sequencers, drivers, and monitors can be reused independently. OVM recommends that environment developers create a more abstract container, agent to emulate and verify DUTdevices. They encapsulate a driver, sequencer, and monitor. Active agents emulate devices and drive transactions according totest directives. Passive agents only monitor DUT activity.
Environment: The environment (env) is the top-level component of the OVC. It contains one or more agents, as wellas other components such as a bus monitor.

to start a general verification process
create a base class for pattern generation
define the control signals
define utility functions
define default constraint for each control signal, e.g. checker, printer..
create a class that inherits the base class
define specific contraints for control signals (if necessary, disable base class's constraints)

ovm provides additional features:
printing
packing
transaction layer recording
...
0. basic functions and usage
** my_class_inst.print(); // print name, type, size, value of vars
** class_inst1.set_name("inst_tst"); // rename the class
** $cast(class_inst2, class_inst1.clone()); // clone
** void '(begin_tr(class_inst); //start of transaction recording
//body
end_tr(class_inst)); //end of recording

1. class definition keyword and usage
** `ovm_object_utils_begin(my_classname)
`ovm_field_int( my_int_var, OVM_ALL_ON)
`ovm_field_enum( my_enum_typename, my_enum_var, OVM_ALL_ON + OVM_NOCOMPARE)
...
`ovm_object_utils_end
== description
** `ovm_object_utils macro implements a set of utility functions for OVM objects: get_type_name() and create() methods implemented, print(), clone(), etc are configured.
** `ovm_field_* macros specify the automation requirements for each field of the data item
** OVM_ALL_ON Turns on the COPY, COMPARE, PRINT, RECORD, PACK , UNPACK and DEEP flags

OVM Message Control
`message( , ( ) )
is a formatted string with arguments similar to $display = OVM_NONE, OVM_LOW, OVM_MEDIUM, OVM_HIGH, OVM_FULL
OVM_LOW shows test scope
Three ways to change verbosity:
1.+MSG_DETAIL argument to irun% irun …. +MSG_DETAIL=NONE
The default verbosity is OVM_LOW
2.In the test:set_report_verbosity_level(int VERBOSITY);
3.TCL APIovm_message command
OVM Data Item
class uart_frame extends ovm_sequence_item;
OVM Sequences
Derived from ovm_sequence base class
Use the `ovm_sequence_utils macro to associate the sequence with the relevant sequencertype and to declare the various automation utilities.
e.g.: class rand_retry_seq extends ovm_sequence;
`over_do
An object is created using the factory settings and assigned to the specifiedvariable. Based on the processing, when the driver requests an item from thesequencer, the item is randomized and provided to the driver.
`over_do_with
Similiar to `over_do. This enables adding different inline constraints, while still using the same item or sequence variable.
The body() task is the actual logic of the sequence.
[0] ovm_random_sequence executes a random number of sequences(does not call itself)
[1] ovm_exhaustive_sequence randomly executes each defined sequence without repetition until all are executed(does not call random or itself)

[2] ovm_simple_sequence executes a single data transaction Default_sequence = ovm_random_sequence
sequence flow
`ovm_do(subsequence);
Call pre_do() task with is_item = 0
Call mid_do()
trigger subsequence.started
Call subsequence.body()
trigger subsequence.ended
Call post_do()
End of do subsequence

The Driver (BFM)
class uart_tx_driver extends ovm_driver;
`ovm_sequence_item item;
uart_frame this_tx_frame;
`ovm_component_utils(uart_tx_driver)

agent
Agents provide all the verification logic for a device in the system. Instantiation and connection logic is done by the developer in a standard manner
–Integrator does not need to worry about this.
Agents share a common configuration or common signals

A Standard agent has:
–Sequencer for generating traffic
–Driver to drive the DUT
–Monitor
e.g.
class master_agent extends ovm_agent;
master_driver driver;
master_sequencer sequencer;
master_monitor monitor;


virtual function void build();


virtual function void connect();


endclass



OVM Simulation Phases


OVM Built-in Phases – run in order


build Build Top-Level Testbench Topology

connect Connect environment topology
start_of_simulation Configure verification components
end_of_elaboration Post-elaboration activity (e.g. print topology)
run task - Run-time execution of the test
extract Gathers details on the final DUT state
check Processes and checks the simulation results.
report Simulation results analysis and reporting

to add a user defined phase, derive a subclass of ovm_phase that implements either the call_task() or call_funcmethod, depending on whether the new phase is to be time-consuming (a task) or not (a function). Register the phase with the OVM phase controller, ovm_top.

Creating and Adding a New Sequence
To create a user-defined sequence:
1. Derive a sequence from the ovm_sequence base class.
2. Use the `ovm_sequence_utils macro to associate the sequence with the relevant sequencer type and to declare the various automation utilities.
This macro is similar to the`ovm_object_utils macro (and its variations) except that it takes another argument, whichis the sequencer type name this sequence is associated with. This macro also provides ap_sequencer variable that is of the type specified by the second argument of the macro. This allows access to derived type-specific sequencer properties.
3. Implement the sequence's body task with the specific scenario you want the sequence to execute.
In the body, you can execute data items and other sequences using “`ovm_do” and“`ovm_do_with”.

Executing Multiple Sequences Concurrently
There are two ways you can create concurrently-executing sequences:
• Using the ovm_do Macros with fork/join.
• Starting Several Sequences in Parallel using the start() method.
Using the ovm_do Macros with fork/join
e.g.:
a_seq a;
b_seq b;
virtual task body();
fork
`ovm_do(a)
`ovm_do(b)
join
endtask : body
Starting Several Sequences in Parallel
a_seq a;
b_seq b;
virtual task body();// Initialize the sequence variables with the factory.
`ovm_create(a)
`ovm_create(b)// Start each subsequence as a new thread.
fork
a.start(p_sequencer);
b.start(p_sequencer);
join
endtask : body

Randomizing the Kind of Generated Sequences
The use of `ovm_sequence_utils registers a sequence type with a particular sequencer’s sequence library. The seq_kind property is used to identify a specific type in the sequence library based on the sequence type. For example, get_seq_kind(“simple_seq_do”) returns an integer that can be used to identify the sequence type simple_seq_do.

A test name is provided to run_test() via a simulator command-line argument. If the top modulecalls run_test() without an argument, the +OVM_TESTNAME=test_name simulator command-line argument is always checked. otherwise a default test_name must be provided.


Virtual sequencer
with virtual sequencer, we can
1. provide sequence to multiple channels that need sequences
2. timing the sequences between channels
how to do:
1. define virtual sequencer class
1.1. define virtual sequencer class that derives from ovm_virtual_sequencer class
   note: use `ovm_update_sequencer_lib to register in new() function
1.2. define 1 or more sequence consumer interfaces (to connect to interface sequencers)
use add_seq_cons_if("my_name")  in build() function to generate interface
these consumer interfaces has built-in function named seq_cons_if(), which can be connected to seq_prod_if of normal sequencer
1.3 instantiate normal sequencer to be attached to
2. define virtual sequences class
each virtual sequence has all possible instance of interface sequences
the instances of interface sequence are activated in virtual task body()  using `ovm_do_seq(seq_name, p_sequencer.seq_cons_if["myname"])
in this way, virtual sequencer take the virtual sequence interface as output explicitly
3. define tb class (extends ovm_threaded_component or ovm_env?) to
connect  virtual sequencer to interface sequencer in the testbench(sve, tb, etc)
3.0 the tb class may extend directly from previous class with all env but without virtual sequencer to simply the process 
3.1. instantiate the virtual sequencer
e.g.: simple_vsequencer vsequencer0;
and build it in the function build()
3.2. connect virtual sequencer's sequence consumer interfaces to the interface sequencers in virtual function connect()
e.g.: agent0.sequencer.seq_prod_if.connect_if(vsequencer0.seq_cons_if["bar"]);
4. define a class extends ovm_test
instantiate the tb class
invoke a virtual sequence
use task set_config_string(), set_config_int() in function build() to configure the virtual sequencer
use following command in task run() to print info
  ovm_factory::print_all_overrides();
  ovm_print_topology();

TLM
TLM – Transaction Level Modeling
TLM is used for Architecture design and (performance) analysis
Interfaces = API’s
interface types
Put interfaces
tlm_blocking_put_if #(type T=int)
tlm_nonblocking_put_if
tlm_put_if
Get interfaces
tlm_blocking_get_if
tlm_nonblocking_get_if
tlm_get_if
Peek interfaces
tlm_blocking_peek_if
tlm_nonblocking_peek_if
tlm_peek_if
Transport interfaces
tlm_blocking_transport_if #(type REQ=int, type RSP=int)
Analysis interface
analysis_if #(type T=int)         non_blocking, broadcast
port vs export
initiator vs target
e.g.
initiator side:
class yapp_m_monitor extends ovm_monitor;
ovm_analysis_port #(yapp_packet) ingress_out= new(“ingress_out", this);
ingress_out.write(collected_packet);

target side:
class sys_monitor extends ovm_threaded_component;
`ovm_analysis_imp_decl(_ingress)
ovm_analysis_imp_ingress#(yapp_packet, sys_mon) ingress_in = new(“sys_mon”, this);
function write_ingress(input yapp_packet packet);

endfunction

testbench side:
class yapp_router_testbench extends ovm_threaded_component;
virtual function void connect();
  input_uvc.master.monitor.ingress_out.connect(router_mod_uvc.sys_mon.ingress_in);
endfunction

python常用命令

本文出自 http://www.dev.idv.tw:8080/mediawiki/index.php/
常用的Python指令

下面列出常用的Python指令及其說明,對於初學Python的人而言應當相當有用:


sys模組:


 argv: 命令列參數。
exit([arg]): 結束程式。
exitfunc: 若有指定此函式,程式結束前會先呼叫此函式。

getopt模組:


 getopt(args, options[, long_options]): 解譯命令列參數選項的工具。

os模組:


 chdir(path): 變更目前工作目錄。
getcwd(): 取得目前工作目錄。
getenv(varname[, defaultValue]): 取得環境變數。
putenv(varname, value): 設定或新增環境變數。
popen(command[, mode[, bufsize] ]): 執行某個命令,並將結果以pipe的方式傳會此程式。
tmpfile(): 傳回一個新的暫存檔案物件,此物件將以"w+b"的mode開啟。
listdir(path): 傳回指定路徑的內容。
remove(path): 刪除指定的檔案。
removedirs(path): 以遞迴的方式刪除指定的路徑。
rename(src, dst): 變更路徑或檔案名稱。
renames(old, new): 遞迴的變更路徑或檔案名稱。
rmdir(path): 非遞迴的方式移除目錄。
stat(path): 傳回指定檔案或路徑的stat結構。
walk(top[, topdown=True [, onerror=None] ]): 產生整個目錄的樹狀結構。
abort(): 對目前的行程產生SIGABRT的訊號。
system(command): 在sub-shell中執行命令。
path.abspath(path): 傳回指定目錄的絕對路徑。
path.join(a, *p): 將兩個或多個路徑名稱結合成一個路徑。並在適當的地方加上目錄分隔字元。
path.exists(path): 檢查檔案或路徑是否存在。
path.basename(path): 傳回路徑的最後一個部分。
path.dirname(path): 傳回檔案名稱中屬於路徑的部分。
path.split(path): 將路徑分割成為各部分。
path.splitdrive(path): 分割出檔案名稱中,關於磁碟機的部分。
path.splitext(path): 分割出檔案名稱中,關於副檔名的部分。
path.splitunc(path): 分割出檔案名稱中屬於UNC的部分。
path.getsize(path): 取得指定檔案的大小。
path.isfile(path): 檢查指定的路徑是否指向一個檔案。
path.isdir(path): 檢查指定的路徑是否為一個目錄。
path.isabs(path): 檢查指定的路徑是否為一個絕對路徑。

shutil模組:


 copy(src, dst): 拷貝src所指定的檔案到dst所指定的檔案中。
copytree(src, dst[, symlinks]): 遞迴的方式將整個src所指定的目錄樹拷貝到dst所指定的地方。
rmtree(path[, ignore_errors[, onerror] ]): 將整個目錄樹下的所有檔案目錄刪除。
move(src, dst): 將整個檔案或目錄搬移到dst所指定的地方。

glob模組:


 glob(pathname): 依照類似於shell在使用的檔案符合檢驗的格式來找出某個目錄下的檔案。

re模組:


 re.compile(pattern[, flags]): 將指定的pattern字串編譯並產生RegExp物件。
regexp.match(string[, pos[, endpos] ]): 若字串與pattern相符,傳回Match物件,否則傳回None。
regexp.search(string[, pos[, endpos] ]): 搜尋字串便找出符合pattern的字串。
regexp.split(string[, maxsplit]): 以pattern作為分割字串,將指定的字串分割成為數個部分。
regexp.sub(repl, string[, count]): 將相符合的字串取得成為另一個字串。
matchObj.group([group1, ...]): 傳回Match物件中的指定群組字串。
matchObj.groups(): 傳回所有的Match物件中的群組。
matchObj.groupdict(): 傳回所有的Match物件中有取名稱的群組。

Saturday, November 8, 2008

python 简明教程

http://www.chinesepython.org/pythonfoundry/tut2.3/tmp/tmp.html
变量和赋值
同一个值可以同时赋给几个变量:
>>> x = y = z = 0
复数也同样得到了支持,虚部由一个后缀"j"或者"J"来表示。带有非零实部的复数记为"real+imagj",也可以通过"complex(real, img)"函数创建
字符串用单引号或双引号标识。可以在行加反斜杠做为继续符。字符串可以用一对三重引号”””或'''来标识
字符串可以用 + 号联接(或者说粘合),也可以用 * 号循环。e.g. '<' + word*5 + '>'。两个字符串值之间的联接是自动的
字符串可以用下标(索引)查询;就像 C 一样,字符串的第一个字符下标是0(zero)
切片索引(Slice indices)可以使用默认值
链表写为中括之间用逗号分隔的一列值(子项)。链表的子项不一定是同一类型的值。
>>> a = ['spam', 'eggs', 100, 1234]
与不变的字符串不同,链表可以改变每个独立元素的值
Control Flow
if ... elif ... elif ... 序列用于替代其它语言中的 switch 或 case 语句。
for 语句依据任意序列(链表或字符串)中的子项,按它们在序列中的顺序来进行迭代
range()生成一个等差级数链表
>>> range(5, 10) [5, 6, 7, 8, 9]
>>> range(0, 10, 3) [0, 3, 6, 9]
>>> range(-10, -100, -30) [-10, -40, -70]
break 语句和 C 中的类似,用于跳出最近的一级 for 或 while 循环。
continue 语句是从 C 中借鉴来的,它表示循环继续执行下一次迭代
pass 语句什么也不做
定义函数
关键字 def 引入了一个函数定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开始,必须是缩进的。函数体的第一行可以是一个字符串值,这个字符串是该函数的 (文档字符串(documentation string)),也可称作 docstring 。
引用参数时,会先从局部符号表中查找,然后是全局符号表,然后是内置命名表。
全局参数虽然可以被引用,但它们不能在函数中直接赋值
函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是传值调用
参数个数可变的函数
1.最有用的形式是给一个或多个参数指定默认值
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
2.函数可以通过参数关键字的形式来调用
parrot(action = 'VOOOOOM', voltage = 1000000)
3.不常用的选择是可以让函数调用可变个数的参数
def fprintf(file, format, *args):
如果要传递的参数已经是一个列表但要调用的函数却接受分开一个个的参数值,在调用函数时加一个 *操作符来自动把参数列表拆开
range(*args)
通过 lambda 关键字,可以创建很小的匿名函数
模块
标准模块
包通常是使用用“圆点模块名”的结构化模块命名空间。例如,名为 A.B 的模块表示了名为 "B" 的包中名为 "A"的子模块。
导入模块时,Python通过 sys.path 中的目录列表来搜索存放包的子目录
包用户可以从包中导入合法的模块,例如: import Sound.Effects.echo
使用 from package import item 方式导入包时,这个子项(item)既可以是包中的一个子模块(或一个子包),也可以是包中定义的其它命名,像函数、类或变量
包支持一个另为特殊的变量, __path__ 。 在包的 __init__.py 文件代码执行之前,该变量初始化一个目录名列表。该变量可以修改,它作用于包中的子包和模块的搜索功能
输入和输出
字符串格式化
标准模块 string包括了一些操作,将字符串填充入给定列时,这些操作很有用
使用 % 操作符,以某个字符串做为其左参数
Python总是把任意值传入 repr() 或 str() 函数,转为字符串。相对而言引号 (``) 等价于repr()
>>> repr(0.1)' 0.10000000000000001'
iterator
大多数容器对象都可以用 for 遍历:
for element in [1, 2, 3]: print element
for element in (1, 2, 3): print element
for element in range(len(data)-1, 1, -1): print element
for key in {'one':1, 'two':2}: print key
for char in "123": print char
for line in open("myfile.txt"): print line
在后台,for 语句在容器对象中调用 iter()。它在容器中逐一访问元素。没有后续的元素时,next() 抛出一个 StopIteration 异常通知 for 语句循环结束。

Class
类定义语法
最简单的类定义形式如下:

class ClassName:

.
.
.


类的定义就像函数定义( def 语句),要先执行才能生效。(你当然可以把它放进 if 语句的某一分支,或者一个函数的内部。)

定义一个类的时候,会创建一个新的命名空间,将其作为局部作用域使用——因此,所以对局部变量的赋值都引入新的命名空间。特别是函数定义将新函数的命名绑定于此。
类对象 Class Objects
类对象支持两种操作:属性引用和实例化
类的实例化使用函数符号。只要将类对象看作是一个返回新的类实例的无参数函数即可。例如:
x = MyClass()
类的实例化操作会自动为新创建的类实例调用 __init__() 方法。可以有参数
实例、方法对象
a method can called immediately like this: x.f()
or stored and used like this: xf = x.f; while True: print xf()
special notes
同名的数据属性会覆盖方法属性,因此应避免可能的命名冲突
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称,但是在调用这个方法的时候你不为这个参数赋值,Python会提供这个值。这个特别的变量指对象本身,按照惯例它的名称是self。但对 Python 而言,self 绝对没有任何特殊含义
继承
派生类的定义如下所示:
class DerivedClassName(BaseClassName):

Python同样有限的支持多继承形式。多继承的类定义形如下例:
class DerivedClassName(Base1, Base2, Base3):

私有变量
Python 对类的私有成员提供了有限的支持。任何形如 __foo随即都被替代为 _classname__foo

Thursday, November 6, 2008

摄影常识和技巧

名词解释
焦距
:镜头光线入射点到焦平面的距离即为焦距。理论上指无限远的景物在焦平面结成清晰影像时,透镜(或透镜组)的第二节点至焦平面的垂直距离。因为第二节点与镜头中心十分接近,通常位于镜头中心略偏后一点点,所以也可以理解为“镜头中心至胶片(现在可叫感光器)平面的距离。
焦距长视角小景深小,焦距短视角大景深大。标准镜头指焦距长度接近相机画幅对角线长度的镜头。对于画幅为24×36mm的135相机的标准镜头焦距为50mm。对于135相机来说,焦距在30mm左右、视角在70°左右称为广角镜头;焦距在22mm左右、视角在90°左右成为超广角镜头。焦距在200mm左右、视角在12°左右的称为远摄(长焦)镜头;焦距在300mm以上,视角在8°以下的称为超远摄(长焦)镜头。
标准镜头:焦距等于或相近于摄影(像)机片幅对角线长度的镜头。摄像机变焦镜头所拍的“ 标准” 范围是指镜头的视场角近似于人们观看电视屏幕的视角。如果看电视的人与图像的距离恰好能使他分辨出电视节目的最细部,这时荧光屏和他的眼睛所成的角度大约为24° ,我们就把视场角24° 定为“ 标准” 镜头。因为看电视者对所处位置的要求并不严格,所以通常认为视场角在15°~30° (相应的焦距约为17~35 mm )
广角镜头:焦距小于而视角大于标准镜头的镜头。对于摄像机来说,视场角大于30° 称为广角镜头(视角30°~50° ,焦距约为9.5~16 mm )
长焦镜头:焦距大于而视角小于标准镜头的镜头。对于摄像机来说,视场角小于15° (焦距约35~143 mm ,视场角4°~15° ),最近成像点要在1 m 左右。
变焦镜头:镜头焦距能在一定的范围内进行有级或无级地变化:
镜头结构
镜头的结构主要指的是构成镜头的镜片数目情况。一个镜头往往是由多块镜片构成,根据需要这些镜片又会组成小组,从而把要拍摄的对象尽可能清晰、准确的还原。由于不同厂商、不同产品采用的技术是不同的,因此绝不能简单的认为镜片的数目多好还是数目少好!不同镜头的镜片数目是用数字标识的,可谓一目了然。比如“佳能 EF28-105/3.5-4.5U”,标识为12组15片,这也就是说,这款镜头共有15片镜片,这15片镜片又分为12个镜头组,有的为1片成组,有的为两片成组,以实现不同的功能。
对同样性能的镜头,一般认为透镜片数多些的成像质量好些,但对性能不同的镜头则不然,如变焦镜头的透镜片数则少得多。然而,定焦镜头的成像质量一般却要高于变焦镜头
快门速度(通光时间):光线照射感光元件时间的长短
B门:手动控制快门速度。
安全快门:所使用的快门速度要等于或大于镜头焦距。
曝光模式(拍摄模式):程序自动(P)、光圈优先(A,aperture)、快门优先(S,shutter)、手动(M)
程序自动曝光:照相机根据测光系统所测得的被摄画面的曝光值,按照厂家生产时所设定的快门及光圈曝光组合,自动地设定快门速度和光圈值
一般P模式曲线都是以50/1.4镜头为准(因为有f/1.4的大光圈),感光度是ISO 100
曝光补偿(EV):拍摄者对相机测光所确定的曝光量进行修正、调整,从而得到自己需要的曝光效果。
曝光补偿的基本原则:“白加黑减”定理。
反射率18%的灰色调是测光表的基准,决定曝光值。
景深:镜头对某一物体聚焦后,在所对焦点前后延伸出来的比较清晰的范围;这种范围,在聚焦点前占1/3,聚焦点后占2/3。
镜头光圈:
光圈值=焦距/光圈直径
光圈值越大光圈越小,相同的曝光时间的进光量就越小,拍摄清晰距离范围的也就越广,反之,范围越小。大光圈的好处有除了可以减少曝光时间过长带来的手抖,和拍高速运动物困难的问题,还可以增加背景虚化,提高照片效果
光圈、焦距与景深
1.与光轴平行的光线射入凸透镜时,理想的镜头应该是所有的光线聚集在焦点后,再以锥状的扩散开来。
2.在焦点前后,光线开始聚集和扩散,点的影象变成模糊的,形成一个扩大的圆,这个圆就叫做弥散圆。
如果弥散圆的直径小于人眼的鉴别能力,在一定范围内实际影象产生的模糊是不能辨认的。这个不能辨认的弥散圆就称为容许弥散圆δ(permissible circle of confusion)。
3.在焦点前后各有一个容许弥散圆,这两个弥散圆之间的距离就叫景深,即:在被摄主体(对焦点)前后,其影像仍然有一段清晰范围的,就是景深。
4.景深随镜头的焦距、光圈值、拍摄距离而变化。对于固定焦距和拍摄距离,使用光圈越小,景深越大。
如果光圈缩小,即通过透镜的光入射角度范围缩小,因此在相同δ条件下,景深随之变大。
5.结论:光圈越大,景深越小。镜头焦距越长,景深越小。拍摄对象距离越远,景深越大

镜头的放大倍率
指拍摄时底片上的成像长度与实物长度的比值。如果实物长度为10毫米,在底片上成像也是5毫米,则镜头放大倍率1:2。如果实物长度为10毫米,在底片上成像也是2毫米,则镜头放大倍率1:5。专用的微距镜头,放大倍率一般都能达到1:1,即拍摄与底片等大的物体,取景时可以放满画面并清晰成像。
风光摄影的构图手法
主要有六个构图的原则
1、平衡:画面的布局采用对称或非对称式。
2、对比:采用大小、高低、远近的对比手法。
3、主题:主题布局在画面的位置突出。
4、画面的连接性:画面的连接性是从线条的连接性和物体中产生,必定要有龙去脉。来龙是画面的引点,而去脉是消失点,这些来去的表现,都是一脉可寻。这样才能有效地表现透视感。
5、画面的节奏:主要也是从景物的线条中产生,有见于画面的直线、曲线、斜线、弧线、上下屈曲线、左右转折的线,有些是明显的实线,也有些是隐晦的虚线;有些是错综复杂,而矛盾统一;有些是简单纯洁,却活泼流动;有些强弱对比,有些刚健有力。这些线条在我们的画面上都能有效地产生着画面的节奏感和连接性。因此,我们在风光摄影中,一定注意运用景物的线条。
6、画面的分格方式:为了使画面的严敕的处理,也可将画面进行分格方式来处理,目的衡量画面布局的份量。

前景、中景和后景的运用
前景:
  如果要表现画面上的透视、立体感、纵深感等,前景是非常重要的了。如果是早晨、晚霞或是阴天,前景色调则较深,但是如果有阳光,且前景的物体色浅,那么又形成背景7深色而前景又显得浅色,这种情况多数是逆光照片。前景往往是注目,所以前景之处理是非常重要的,是风光照片成败所在,对于前景要特别注意。有些风光照片在放大时还加上前景,加强风光照片之表现力。
中景:
  通常一张风光照片的主体都是放在前景与中景之间,所以中景的处理亦非常重要。有些照片的主体则在中景,是色调变化的中心地区,运用前景和远景为中景服务,能达到表达主题思想的目的,但是主体位置亦不能过于正中,而放在中间的左或右侧,这样较为活泼。如果主体在正中,很容易犯着四面的景物重重包围,而弄到局促不安、呆滞而缺乏生气。
远景:
  远景之作用将风光的景物扩展开去足以烘托意境的气氛,加强画面的美,增加人们的想象力和感染力,远景的色调以浅色调的居多,中色调和深色调也有,不过很少。
  但是从整幅风光照片来看,未必前景、中景和远景都有,有些只有近景和远景,有些只有中景和远景,那就看具体情况了。

取景和如何取角度?
  一幅完美的风光照片,除了要有表现主题的主要景物以外,还应该有其他的物体作为衬托。这主要景物和衬托的物体在摄影术语中就叫做主体和陪体,物体是有主次之分,在画面上就应有适当的安排,一般是把主体安排在画面上重要而明显的地位,陪体只位于画上或上或下,或左右的一部分地方。绝不能把陪体彼此要互相联系互相呼应,不然就会形成一个主、次分散的画面了。
  有显著建筑物作为景物目标的风光,应当以建筑物作为主体,有些景物的主体物不只是一个而是很多个,甚至可以占满整个画面。我们拍摄这类景物时,首先要决定它在画面上应该占有的位置,然后决定采取的数量,再选择拍摄的镜头角度。
  没有建筑物作景物目标的自然风光的景物是比较多的,正因为它没有固定的景物目标,所以自然风光的景物范围就比较广,可取的拍摄位置也比较灵活,在没有固定主体目标的自然风光里,应根据景物的自然条件并结合理想的太阳光线来决定景物范围和拍摄角度。例如桂林山水风光,山川必然有山有水,究竟应以山作主体,还是以水作为主体呢?这就要根据所拍摄的景物情况来决定了。如果河流近而山层远的山川风景,就应以河流作主体,反之,则应以山作为主体。拍摄以河流为主体的照片时,必须把河流安排在画面上最明显的地位,把远山安排在河流的远处或两旁,作为陪衬河流的陪体。河流景物的水平线一般都是很明显的,最容易把画面划分为二,影响宾主物体的联系。因此,如果采取的河流是横过画的,它的水平线必须很明显,我们就要选择有明显直线条的物体(如木船、桅杆和可作近景物的树木枝干等)冲破横的水平线,或以较远距离的船艇作为近景。如果采取的河流是弯曲的,它的水平线就不会很明显地划分画面。但为了显示出河流的深远,就应站在较高的位置以俯视角度拍摄。这样不但能显示景物的深远,使弯曲的水平线在画上形成弧线而增加了线条的美感。
山川风景也有不少山近而河远的,这就必须以山为主,以河为辅。山必然高于河,在山近河远的情况下,站在山下不但不能看见河流,也不会完全看见山层的面貌。因此,拍摄山近河远的景物,就必须站在高山上,采取山层作为主体,用俯视角度拍摄,使白色的远河在山层间呈现。
  拍摄没有河流可见的山层景色,可站在高山上摄取山层为远景,也可站在山下拍摄山形。应采取一些适当 的景物作山景的陪衬,才会在画面上形成孤山的感觉。表现出高耸雄伟或山峦峻秀的气势,也要寻取适合衬托高山的物体,使山景在画面上显现得更美而不至于枯燥无味。
  森林与原野同是属于自然风光的景物,也是没有个别固定景物目标的风光。森林的景象是随着不同的季节而变化的,原野也会因不同的生产情况有不同的场面。例如森林里的树木在四季中有它不同的色调和疏密程序,原野上有数不尽的牛、马、羊群或各种丰茂的庄稼(植物园、龙胜季节),森林与原野虽同是适宜用大场面表现景物,但森林与原野的取景方法就应有所不同。拍摄森林需要身处林中,选取有远有近,有高有低,有疏有密的树木场面,以平视的镜头角度拍摄,才能在画面上显示出广阔、深远的森林面貌。如果站在林外拍摄,在画面上就只能见于是一片密密的颜色沉重的树林,不仅与天空的色调极不调和,而且没有景物的深度感。原野是一片平地,如果不站立在适当的高位以俯拍摄,也同样不能把原野上的生活现象全面表现出来。
  城市风光是以街道和建筑物为主的风景,每个城市都有它的不同地主特点和内容。拍摄城市风光,必须着重表现出这个城市的地方特色和繁荣景色。拍摄城市风光就要根据它们不同地方特点选择镜头。例如上海是一个江岸而又是我国最大的城市,水道交通畅通国内外,堤岸一带高大的楼房也比较集中。拍摄上海城市风光,就应选择能表现上海特点和规模的外滩作为拍摄重点,如北京、广州,杭州。但拍摄堤岸城市的市景要有适当高度的立足点(站在四、五楼为宜),站在过高或过低拍摄具有较近楼房的景物,容易造成楼房线条不平正,变形的效果。市区其它繁华、热闹的地区,要寻找较高的拍摄位置来表现它的热闹情景(如灯光夜市),观察其能否表现出繁华、热闹的街道结合在一起拍摄,因为这样既能表现出这个地方的特点,又说明它的繁荣,拍摄出气氛较好的城市风光作品。
  拍摄农村风光应结合农村的优美环境,尽可利用可拍摄的范围而显示出农村广阔的面貌。农村的房屋一般都不很高,而且较为聚集,如果站在村庄附近的山坡上,就可以把它很好地表现出来。因此,拍摄时为了呈现农村的面貌和深远丰茂的庄稼,表现田园的线条等。最好寻找较高的山坡为立足点(龙胜),其次,利用一年四季农村不同的景色、农作物、色块等作有利的拍摄选择。

光线在景物上的效果如何把握
  光是摄影的生命,没有光线就不可能存在有摄影。摄影的艺术是光与影的艺术。大家都知道,风景中的景物和其他东西一样,有了光线的照射,才会产生明暗层次、线条和色调。拍摄风光,主要是以太阳光作为光源。太阳光线是一种变化多端的东西,它照射在景物上,能产生各种不同的效果。它有时强有时弱,而且还会随着季节和气候的不同而变化,景物就因为它的不同变化而受到不同影响。因此,我们拍摄景物时,就先要了解每种光线的来源和光线的强弱给予的影响,从而很好地加以运用,才能充分表达景物的光线效果。风光照片拍摄得成功与否,与光线运用得是否得当有很大关系。因此,熟悉光线在景物上的一切变化,是拍摄风光照片的一个关键问题。

1、正面光对景物的效果
  用正面光拍摄景物,可使景物清朗而具有光亮、鲜明的气氛。但正面光照射在景物上过于平正必须缺乏明暗之分,往往会使景物主体与背景的色调互相混淆起来,缺乏景物的立体效果

2、侧光对景物的效果
利用侧光拍摄景物,由于光线斜照景物,景物自然会产生阴影,显现明暗的线条,使景物有立体的感觉。景物有了立体感,立体瑟背景的色调就不易互相混淆,但拍摄侧光景物,要注意阴暗部分色高的深浅,以阴暗部分确定光时间,但最好以中性灰为测光基调,使景物阴暗部分的层次能够充分显示出来,使画面层次丰富。侧光是几种基本光线中最能表现层次、线条的光线,也是最适宜拍摄风光照片的采光。

3、逆光对景物的效果
  逆光照射景物,景物中被光线照射的部分,都会产生光亮的轮廓因而就能使物体与物体之间都有明显的光的界线,不会使主体与背景互相混合成一片深黑色的色调。因为逆光所造成的这种光亮的轮廓使主体与背景物截然分开,这就是逆光所独有的特点。
  逆光是从景物背后照射来的,我们拍摄的对象必然是没有直接光线照射的阴暗部分,因而也就不容易表现出景物的明暗层次和线条。但是逆光照射在一切物体的背后,如果物体与物体之间距离不很远,就有互相反射光线的作用。拍摄逆光景物往往会因光亮的轮廓和镜头前面的光照影响拍摄者的视觉,容易造成曝光不足。因此,拍摄逆光景物必然以景物的阴暗部分或中性灰来确定曝光时间,才能充分显示出景物的层次。另外,逆光照射下的平地、水面以及一切仰面物体,自然会产生一片强烈的白色反光,为了避免这部分与其他物体色调反差过大,以运用柔和的光线拍摄较为适宜。

4、高光对景物的效果
  太阳升至在天空垂直地照射大地时,就是高光。高光是一天中阳光最强烈的时候,因此,光线强烈,阴影必深。同时高光又是从高空垂直照射下来的光线,除了能表现由上到下的阴暗层次外,并不能表现出物体的质感,这种光线不是拍摄风光的理想光源,非必要时拍摄的景物,应尽量避免采用高光

5、散射光、低光、反光对景的效果
  除了以上介绍正面光、侧光、逆光和高光四种基本光线类型之处,有时也要在散射光下拍摄景物。散射光就没有直接阳光照射,在这种光线下拍摄,被摄的一切物体必须没有明暗的线条界线,不能产生阴影。因此,我们也就不利用光线来变化景物主体及背景调的深浅。散射光下拍摄景物只能显示出平淡的物体影像和阴沉的气氛,不能在景物上产生明暗的层次和线条的美。因此,有时需要拍摄景物而遇到散射光的天气,那就只有尽可能缩小景物范围而采取较近距离的中景或局部场面,才可获得稍为清晰的效果。场面越大,灰暗的气氛越浓;场面越小,灰暗的色调越小。
  太阳刚出或将落的时候,是一天中最柔和的低光光线,由于光线从低角度直接照射景物,也可在不同的方面而获得正面光、侧光或逆光等几光线的效果。因此,利用低光拍摄风光照片,不但能获得极其柔和的效果,而且富于变化。但低光属于光谱中的红色成分,表现出来的颜色呈黄、橙色,对景物原来有色调会有一定影响。因此利用低光拍摄景物,首先要注意光线对景物色调的影响,然后决定是否适合运用滤色镜拍摄,使有色的低光光线不至于影响景物原有色调。
  反射光是间接的光线,比直接的低光更柔和,但它只能对景物中物体的阴暗部分起反射作用,因为反射范围是有限度的,所以它除去能辅助物体本身阴暗部分的表现外是起不了很大作用(加偏振镜)。
  光线对景物的层次、线条、色调和气氛都有着直接的影响,景物在照片中能否表现得好,全赖于运用光线。因此,我们必须了解每一种光线对景物的作用,才能获得理想的效果。我们只有经常地观察各种光线在景物中的自然变化和影响,才有助于我们对光线效果的认识。

Tuesday, October 21, 2008

python regular expression

 

   
 

Python正则表达式操作指南


 

出自Ubuntu中文


 

 
 

原文出处:http://www.amk.ca/python/howto/regex/

原文作者:A.M. Kuchling (amk@amk.ca)

授权许可:创作共用协议

翻译人员:FireHare

校对人员:Leal

适用版本:Python 1.5 及后续版本




摘要



本文是通过Python的 re 模块来使用正则表达式的一个入门教程,和库参考手册的对应章节相比,更为浅显易懂、循序渐进。

本文可以从 http://www.amk.ca/python/howto 捕获



目录




目录




[编辑] 简介


Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。Python 1.5之前版本则是通过 regex 模块提供 Emecs 风格的模式。Emacs 风格模式可读性稍差些,而且功能也不强,因此编写新代码时尽量不要再使用 regex 模块,当然偶尔你还是可能在老代码里发现其踪影。



就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。使用这个小型语言,你可以为想要匹配的相应字符串集指定规则;该字符串集可能包含英文语句、e-mail地址、TeX命令或任何你想搞定的东西。然后你可以问诸如“这个字符串匹配该模式吗?”或“在这个字符串中是否有部分匹配该模式呢?”。你也可以使用 RE 以各种方式来修改或分割字符串。



正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。在高级用法中,也许还要仔细留意引擎是如何执行给定 RE ,如何以特定方式编写 RE 以令生产的字节码运行速度更快。本文并不涉及优化,因为那要求你已充分掌握了匹配引擎的内部机制。



正则表达式语言相对小型和受限(功能有限),因此并非所有字符串处理都能用正则表达式完成。当然也有些任务可以用正则表达式完成,不过最终表达式会变得异常复杂。碰到这些情形时,编写 Python 代码进行处理可能反而更好;尽管 Python 代码比一个精巧的正则表达式要慢些,但它更易理解。


[编辑] 简单模式


我们将从最简单的正则表达式学习开始。由于正则表达式常用于字符串操作,那我们就从最常见的任务:字符匹配 下手。



有关正则表达式底层的计算机科学上的详细解释(确定性和非确定性有限自动机),你可以查阅编写编译器相关的任何教科书。


字符匹配


大多数字母和字符一般都会和自身匹配。例如,正则表达式 test 会和字符串“test”完全匹配。(你也可以使用大小写不敏感模式,它还能让这个 RE 匹配“Test”或“TEST”;稍后会有更多解释。)


这个规则当然会有例外;有些字符比较特殊,它们和自身并不匹配,而是会表明应和一些特殊的东西匹配,或者它们会影响到 RE 其它部分的重复次数。本文很大篇幅专门讨论了各种元字符及其作用。


这里有一个元字符的完整列表;其含义会在本指南馀下部分进行讨论。


. ^ $ * + ? { [ ] \ | ( )

我们首先考察的元字符是"[" 和 "]"。它们常用来指定一个字符类别,所谓字符类别就是你想匹配的一个字符集。字符可以单个列出,也可以用“-”号分隔的两个给定字符来表示一个字符区间。例如,[abc] 将匹配"a", "b", 或 "c"中的任意一个字符;也可以用区间[a-c]来表示同一字符集,和前者效果一致。如果你只想匹配小写字母,那么 RE 应写成 [a-z].


元字符在类别里并不起作用。例如,[akm$]将匹配字符"a", "k", "m", 或 "$" 中的任意一个;"$"通常用作元字符,但在字符类别里,其特性被除去,恢复成普通字符。


你可以用补集来匹配不在区间范围内的字符。其做法是把"^"作为类别的首个字符;其它地方的"^"只会简单匹配 "^"字符本身。例如,[^5] 将匹配除 "5" 之外的任意字符。


也许最重要的元字符是反斜杠"\"。 做为 Python 中的字符串字母,反斜杠后面可以加不同的字符以表示不同特殊意义。它也可以用于取消所有的元字符,这样你就可以在模式中匹配它们了。举个例子,如果你需要匹配字符 "[" 或 "\",你可以在它们之前用反斜杠来取消它们的特殊意义: \[ 或 \\。


一些用 "\" 开始的特殊字符所表示的预定义字符集通常是很有用的,象数字集,字母集,或其它非空字符集。下列是可用的预设特殊字符:



\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]。




这样特殊字符都可以包含在一个字符类中。如,[\s,.]字符类将匹配任何空白字符或","或"."。


本节最后一个元字符是 . 。它匹配除了换行字符外的任何字符,在 alternate 模式(re.DOTALL)下它甚至可以匹配换行。"." 通常被用于你想匹配“任何字符”的地方。


[编辑] 重复


正则表达式第一件能做的事是能够匹配不定长的字符集,而这是其它能作用在字符串上的方法所不能做到的。 不过,如果那是正则表达式唯一的附加功能的话,那么它们也就不那么优秀了。它们的另一个功能就是你可以指定正则表达式的一部分的重复次数。

我们讨论的第一个重复功能的元字符是 *。* 并不匹配字母字符 "*";相反,它指定前一个字符可以被匹配零次或更多次,而不是只有一次。

举个例子,ca*t 将匹配 "ct" (0 个 "a" 字符), "cat" (1 个 "a"), "caaat" (3 个 "a" 字符)等等。RE 引擎有各种来自 C 的整数类型大小的内部限制,以防止它匹配超过2亿个 "a" 字符;你也许没有足够的内存去建造那么大的字符串,所以将不会累计到那个限制。

象 * 这样地重复是“贪婪的”;当重复一个 RE 时,匹配引擎会试着重复尽可能多的次数。如果模式的后面部分没有被匹配,匹配引擎将退回并再次尝试更小的重复。



一步步的示例可以使它更加清晰。让我们考虑表达式 a[bcd]*b。它匹配字母 "a",零个或更多个来自类 [bcd]中的字母,最后以 "b" 结尾。现在想一想该 RE 对字符串 "abcbd" 的匹配。


















StepMatchedExplanation
1aa 匹配模式
2abcbd引擎匹配 [bcd]*,并尽其所能匹配到字符串的结尾
3Failure引擎尝试匹配 b,但当前位置已经是字符的最后了,所以失败
4abcb退回,[bcd]*尝试少匹配一个字符。
5Failure再次尝次b,但在当前最后一位字符是"d"。
6abc再次退回,[bcd]*只匹配 "bc"。
7abcb再次尝试 b ,这次当前位上的字符正好是 "b"

RE 的结尾部分现在可以到达了,它匹配 "abcb"。这证明了匹配引擎一开始会尽其所能进行匹配,如果没有匹配然后就逐步退回并反复尝试 RE 剩下来的部分。直到它退回尝试匹配 [bcd] 到零次为止,如果随后还是失败,那么引擎就会认为该字符串根本无法匹配 RE 。



另一个重复元字符是 +,表示匹配一或更多次。请注意 * 和 + 之间的不同;* 匹配零或更多次,所以根本就可以不出现,而 + 则要求至少出现一次。用同一个例子,ca+t 就可以匹配 "cat" (1 个 "a"), "caaat" (3 个 "a"), 但不能匹配 "ct"。



还有更多的限定符。问号 ? 匹配一次或零次;你可以认为它用于标识某事物是可选的。例如:home-?brew 匹配 "homebrew" 或 "home-brew"。



最复杂的重复限定符是 {m,n},其中 m 和 n 是十进制整数。该限定符的意思是至少有 m 个重复,至多到 n 个重复。举个例子,a/{1,3}b 将匹配 "a/b","a//b" 和 "a///b"。它不能匹配 "ab" 因为没有斜杠,也不能匹配 "a////b" ,因为有四个。



你可以忽略 m 或 n;因为会为缺失的值假设一个合理的值。忽略 m 会认为下边界是 0,而忽略 n 的结果将是上边界为无穷大 -- 实际上是先前我们提到的 2 兆,但这也许同无穷大一样。



细心的读者也许注意到其他三个限定符都可以用这样方式来表示。 {0,} 等同于 *,{1,} 等同于 +,而{0,1}则与 ? 相同。如果可以的话,最好使用 *,+,或?。很简单因为它们更短也再容易懂。


[编辑] 使用正则表达式


现在我们已经看了一些简单的正则表达式,那么我们实际在 Python 中是如何使用它们的呢? re 模块提供了一个正则表达式引擎的接口,可以让你将 REs 编译成对象并用它们来进行匹配。


[编辑] 编译正则表达式


正则表达式被编译成 `RegexObject` 实例,可以为不同的操作提供方法,如模式匹配搜索或字符串替换。


#!python

>>> import re
>>> p = re.compile('ab*')
>>> print p
<re.RegexObject instance at 80b4150>

re.compile() 也接受可选的标志参数,常用来实现不同的特殊功能和语法变更。我们稍后将查看所有可用的设置,但现在只举一个例子:


#!python

>>> p = re.compile('ab*', re.IGNORECASE)

RE 被做为一个字符串发送给 re.compile()。REs 被处理成字符串是因为正则表达式不是 Python 语言的核心部分,也没有为它创建特定的语法。(应用程序根本就不需要 REs,因此没必要包含它们去使语言说明变得臃肿不堪。)而 re 模块则只是以一个 C 扩展模块的形式来被 Python 包含,就象 socket 或 zlib 模块一样。



将 REs 作为字符串以保证 Python 语言的简洁,但这样带来的一个麻烦就是象下节标题所讲的。


[编辑] 反斜杠的麻烦


在早期规定中,正则表达式用反斜杠字符 ("\") 来表示特殊格式或允许使用特殊字符而不调用它的特殊用法。这就与 Python 在字符串中的那些起相同作用的相同字符产生了冲突。



让我们举例说明,你想写一个 RE 以匹配字符串 "\section",可能是在一个 LATEX 文件查找。为了要在程序代码中判断,首先要写出想要匹配的字符串。接下来你需要在所有反斜杠和元字符前加反斜杠来取消其特殊意义。










字符阶段
\section 要匹配的字符串
\\section为 re.compile 取消反斜杠的特殊意义
"\\\\section"为字符串取消反斜杠



简单地说,为了匹配一个反斜杠,不得不在 RE 字符串中写 '\\\\',因为正则表达式中必须是 "\\",而每个反斜杠按 Python 字符串字母表示的常规必须表示成 "\\"。在 REs 中反斜杠的这个重复特性会导致大量重复的反斜杠,而且所生成的字符串也很难懂。



解决的办法就是为正则表达式使用 Python 的 raw 字符串表示;在字符串前加个 "r" 反斜杠就不会被任何特殊方式处理,所以 r"\n" 就是包含"\" 和 "n" 的两个字符,而 "\n" 则是一个字符,表示一个换行。正则表达式通常在 Python 代码中都是用这种 raw 字符串表示。










常规字符串Raw 字符串
"ab*"r"ab*"
"\\\\section"r"\\section"
"\\w+\\s+\\1"r"\w+\s+\1"

执行匹配


一旦你有了已经编译了的正则表达式的对象,你要用它做什么呢?`RegexObject` 实例有一些方法和属性。这里只显示了最重要的几个,如果要看完整的列表请查阅 Python Library Reference












方法/属性作用
match()决定 RE 是否在字符串刚开始的位置匹配
search()扫描字符串,找到这个 RE 匹配的位置
findall()找到 RE 匹配的所有子串,并把它们作为一个列表返回
finditer()找到 RE 匹配的所有子串,并把它们作为一个迭代器返回



如果没有匹配到的话,match() 和 search() 将返回 None。如果成功的话,就会返回一个 `MatchObject` 实例,其中有这次匹配的信息:它是从哪里开始和结束,它所匹配的子串等等。



你可以用采用人机对话并用 re 模块实验的方式来学习它。如果你有 Tkinter 的话,你也许可以考虑参考一下 Tools/scripts/redemo.py,一个包含在 Python 发行版里的示范程序。




首先,运行 Python 解释器,导入 re 模块并编译一个 RE:



#!python

Python 2.2.2 (#1, Feb 10 2003, 12:57:01)
>>> import re
>>> p = re.compile('[a-z]+')
>>> p
<_sre.SRE_Pattern object at 80c3c28>

现在,你可以试着用 RE 的 [a-z]+ 去匹配不同的字符串。一个空字符串将根本不能匹配,因为 + 的意思是 “一个或更多的重复次数”。 在这种情况下 match() 将返回 None,因为它使解释器没有输出。你可以明确地打印出 match() 的结果来弄清这一点。


#!python

>>> p.match("")
>>> print p.match("")
None

现在,让我们试着用它来匹配一个字符串,如 "tempo"。这时,match() 将返回一个 MatchObject。因此你可以将结果保存在变量里以便後面使用。


#!python

>>> m = p.match( 'tempo')
>>> print m
<_sre.SRE_Match object at 80c4f68>

现在你可以查询 `MatchObject` 关于匹配字符串的相关信息了。MatchObject 实例也有几个方法和属性;最重要的那些如下所示:












方法/属性作用
group()返回被 RE 匹配的字符串
start()返回匹配开始的位置
end()返回匹配结束的位置
span()返回一个元组包含匹配 (开始,结束) 的位置



试试这些方法不久就会清楚它们的作用了:


#!python

>>> m.group()
'tempo'
>>> m.start(), m.end()
(0, 5)
>>> m.span()
(0, 5)

group() 返回 RE 匹配的子串。start() 和 end() 返回匹配开始和结束时的索引。span() 则用单个元组把开始和结束时的索引一起返回。因为匹配方法检查到如果 RE 在字符串开始处开始匹配,那幺 start() 将总是为零。然而, `RegexObject` 实例的 search 方法扫描下面的字符串的话,在这种情况下,匹配开始的位置就也许不是零了。


#!python

>>> print p.match('::: message')
None
>>> m = p.search('::: message') ; print m
<re.MatchObject instance at 80c9650>
>>> m.group()
'message'
>>> m.span()
(4, 11)

在实际程序中,最常见的作法是将 `MatchObject` 保存在一个变量里,然後检查它是否为 None,通常如下所示:


#!python

p = re.compile( ... )
m = p.match( 'string goes here' )
if m:
print 'Match found: ', m.group()
else:
print 'No match'

两个 `RegexObject` 方法返回所有匹配模式的子串。findall()返回一个匹配字符串行表:


#!python

>>> p = re.compile('\d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
['12', '11', '10']

findall() 在它返回结果时不得不创建一个列表。在 Python 2.2中,也可以用 finditer() 方法。


#!python

>>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')
>>> iterator
<callable-iterator object at 0x401833ac>
>>> for match in iterator:
... print match.span()
...
(0, 2)
(22, 24)
(29, 31)

[编辑] 模块级函数


你不一定要产生一个 `RegexObject` 对象然后再调用它的方法;re 模块也提供了顶级函数调用如 match()、search()、sub() 等等。这些函数使用 RE 字符串作为第一个参数,而后面的参数则与相应 `RegexObject` 的方法参数相同,返回则要么是 None 要么就是一个 `MatchObject` 的实例。


#!python

>>> print re.match(r'From\s+', 'Fromage amk')
None
>>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998')
<re.MatchObject instance at 80c5978>

Under the hood, 这些函数简单地产生一个 RegexOject 并在其上调用相应的方法。它们也在缓存里保存编译后的对象,因此在将来调用用到相同 RE 时就会更快。



你将使用这些模块级函数,还是先得到一个 `RegexObject` 再调用它的方法呢?如何选择依赖于怎样用 RE 更有效率以及你个人编码风格。如果一个 RE 在代码中只做用一次的话,那么模块级函数也许更方便。如果程序包含很多的正则表达式,或在多处复用同一个的话,那么将全部定义放在一起,在一段代码中提前编译所有的 REs 更有用。从标准库中看一个例子,这是从 xmllib.py 文件中提取出来的:


#!python

ref = re.compile( ... )
entityref = re.compile( ... )
charref = re.compile( ... )
starttagopen = re.compile( ... )

我通常更喜欢使用编译对象,甚至它只用一次,but few people will be as much of a purist about this as I am。


[编辑] 编译标志


编译标志让你可以修改正则表达式的一些运行方式。在 re 模块中标志可以使用两个名字,一个是全名如 IGNORECASE,一个是缩写,一字母形式如 I。(如果你熟悉 Perl 的模式修改,一字母形式使用同样的字母;例如 re.VERBOSE的缩写形式是 re.X。)多个标志可以通过按位 OR-ing 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:



这有个可用标志表,对每个标志后面都有详细的说明。














标志含义
DOTALL, S使 . 匹配包括换行在内的所有字符
IGNORECASE, I使匹配对大小写不敏感
LOCALE, L 做本地化识别(locale-aware)匹配
MULTILINE, M多行匹配,影响 ^ 和 $
VERBOSE, X能够使用 REs 的 verbose 状态,使之被组织得更清晰易懂

I

IGNORECASE

使匹配对大小写不敏感;字符类和字符串匹配字母时忽略大小写。举个例子,[A-Z]也可以匹配小写字母,Spam 可以匹配 "Spam", "spam", 或 "spAM"。这个小写字母并不考虑当前位置。

L

LOCALE

影响 \w, \W, \b, 和 \B,这取决于当前的本地化设置。

locales 是 C 语言库中的一项功能,是用来为需要考虑不同语言的编程提供帮助的。举个例子,如果你正在处理法文文本,你想用 \w+ 来匹配文字,但 \w 只匹配字符类 [A-Za-z];它并不能匹配 "é" 或 "ç"。如果你的系统配置适当且本地化设置为法语,那么内部的 C 函数将告诉程序 "é" 也应该被认为是一个字母。当在编译正则表达式时使用 LOCALE 标志会得到用这些 C 函数来处理 \w 后的编译对象;这会更慢,但也会象你希望的那样可以用 \w+ 来匹配法文文本。

M

MULTILINE



(此时 ^ 和 $ 不会被解释; 它们将在 4.1 节被介绍.)



使用 "^" 只匹配字符串的开始,而 $ 则只匹配字符串的结尾和直接在换行前(如果有的话)的字符串结尾。当本标志指定后, "^" 匹配字符串的开始和字符串中每行的开始。同样的, $ 元字符匹配字符串结尾和字符串中每行的结尾(直接在每个换行之前)。

S

DOTALL

使 "." 特殊字符完全匹配任何字符,包括换行;没有这个标志, "." 匹配除了换行外的任何字符。

X

VERBOSE



该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之后;这可以让你更清晰地组织和缩进 RE。它也可以允许你将注释写入 RE,这些注释会被引擎忽略;注释用 "#"号 来标识,不过该符号不能在字符串或反斜杠之后。



举个例子,这里有一个使用 re.VERBOSE 的 RE;看看读它轻松了多少?


#!python

charref = re.compile(r"""
&[[]] # Start of a numeric entity reference
(
[0-9]+[^0-9] # Decimal form
| 0[0-7]+[^0-7] # Octal form
| x[0-9a-fA-F]+[^0-9a-fA-F] # Hexadecimal form
)
""", re.VERBOSE)

没有 verbose 设置, RE 会看起来象这样:


#!python

charref = re.compile("&#([0-9]+[^0-9]"
"|0[0-7]+[^0-7]"
"|x[0-9a-fA-F]+[^0-9a-fA-F])")

在上面的例子里,Python 的字符串自动连接可以用来将 RE 分成更小的部分,但它比用 re.VERBOSE 标志时更难懂。


[编辑] 更多模式功能


到目前为止,我们只展示了正则表达式的一部分功能。在本节,我们将展示一些新的元字符和如何使用组来检索被匹配的文本部分。




[编辑] 更多的元字符


还有一些我们还没展示的元字符,其中的大部分将在本节展示。



剩下来要讨论的一部分元字符是零宽界定符(zero-width assertions)。它们并不会使引擎在处理字符串时更快;相反,它们根本就没有对应任何字符,只是简单的成功或失败。举个例子, \b 是一个在单词边界定位当前位置的界定符(assertions),这个位置根本就不会被 \b 改变。这意味着零宽界定符(zero-width assertions)将永远不会被重复,因为如果它们在给定位置匹配一次,那么它们很明显可以被匹配无数次。

|



可选项,或者 "or" 操作符。如果 A 和 B 是正则表达式,A|B 将匹配任何匹配了 "A" 或 "B" 的字符串。| 的优先级非常低,是为了当你有多字符串要选择时能适当地运行。Crow|Servo 将匹配"Crow" 或 "Servo", 而不是 "Cro", 一个 "w" 或 一个 "S", 和 "ervo"。



为了匹配字母 "|",可以用 \|,或将其包含在字符类中,如[|]。

^



匹配行首。除非设置 MULTILINE 标志,它只是匹配字符串的开始。在 MULTILINE 模式里,它也可以直接匹配字符串中的每个换行。



例如,如果你只希望匹配在行首单词 "From",那么 RE 将用 ^From。


#!python

>>> print re.search('^From', 'From Here to Eternity')
<re.MatchObject instance at 80c1520>
>>> print re.search('^From', 'Reciting From Memory')
None

$



匹配行尾,行尾被定义为要么是字符串尾,要么是一个换行字符后面的任何位置。


#!python

>>> print re.search('}$', '{block}')
<re.MatchObject instance at 80adfa8>
>>> print re.search('}$', '{block} ')
None
>>> print re.search('}$', '{block}\n')
<re.MatchObject instance at 80adfa8>

匹配一个 "$",使用 \$ 或将其包含在字符类中,如[$]。

\A



只匹配字符串首。当不在 MULTILINE 模式,\A 和 ^ 实际上是一样的。然而,在 MULTILINE 模式里它们是不同的;\A 只是匹配字符串首,而 ^ 还可以匹配在换行符之后字符串的任何位置。

\Z

Matches only at the end of the string.
只匹配字符串尾。

\b

单词边界。这是个零宽界定符(zero-width assertions)只用以匹配单词的词首和词尾。单词被定义为一个字母数字序列,因此词尾就是用空白符或非字母数字符来标示的。



下面的例子只匹配 "class" 整个单词;而当它被包含在其他单词中时不匹配。


#!python

>>> p = re.compile(r'\bclass\b')
>>> print p.search('no class at all')
<re.MatchObject instance at 80c8f28>
>>> print p.search('the declassified algorithm')
None
>>> print p.search('one subclass is')
None

当用这个特殊序列时你应该记住这里有两个微妙之处。第一个是 Python 字符串和正则表达式之间最糟的冲突。在 Python 字符串里,"\b" 是反斜杠字符,ASCII值是8。如果你没有使用 raw 字符串时,那么 Python 将会把 "\b" 转换成一个回退符,你的 RE 将无法象你希望的那样匹配它了。下面的例子看起来和我们前面的 RE 一样,但在 RE 字符串前少了一个 "r" 。


#!python

>>> p = re.compile('\bclass\b')
>>> print p.search('no class at all')
None
>>> print p.search('\b' + 'class' + '\b')
<re.MatchObject instance at 80c3ee0>

第二个在字符类中,这个限定符(assertion)不起作用,\b 表示回退符,以便与 Python 字符串兼容。

\B



另一个零宽界定符(zero-width assertions),它正好同 \b 相反,只在当前位置不在单词边界时匹配。


[编辑] 分组


你经常需要得到比 RE 是否匹配还要多的信息。正则表达式常常用来分析字符串,编写一个 RE 匹配感兴趣的部分并将其分成几个小组。举个例子,一个 RFC-822 的头部用 ":" 隔成一个头部名和一个值,这就可以通过编写一个正则表达式匹配整个头部,用一组匹配头部名,另一组匹配头部值的方式来处理。



组是通过 "(" 和 ")" 元字符来标识的。 "(" 和 ")" 有很多在数学表达式中相同的意思;它们一起把在它们里面的表达式组成一组。举个例子,你可以用重复限制符,象 *, +, ?, 和 {m,n},来重复组里的内容,比如说(ab)* 将匹配零或更多个重复的 "ab"。


#!python

>>> p = re.compile('(ab)*')
>>> print p.match('ababababab').span()
(0, 10)

组用 "(" 和 ")" 来指定,并且得到它们匹配文本的开始和结尾索引;这就可以通过一个参数用 group()、start()、end() 和 span() 来进行检索。组是从 0 开始计数的。组 0 总是存在;它就是整个 RE,所以 `MatchObject` 的方法都把组 0 作为它们缺省的参数。稍后我们将看到怎样表达不能得到它们所匹配文本的 span。


#!python

>>> p = re.compile('(a)b')
>>> m = p.match('ab')
>>> m.group()
'ab'
>>> m.group(0)
'ab'

小组是从左向右计数的,从1开始。组可以被嵌套。计数的数值可以能过从左到右计算打开的括号数来确定。


#!python

>>> p = re.compile('(a(b)c)d')
>>> m = p.match('abcd')
>>> m.group(0)
'abcd'
>>> m.group(1)
'abc'
>>> m.group(2)
'b'

group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。


#!python

>>> m.group(2,1,2)
('b', 'abc', 'b')

The groups() 方法返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。


#!python

>>> m.groups()
('abc', 'b')

模式中的逆向引用允许你指定先前捕获组的内容,该组也必须在字符串当前位置被找到。举个例子,如果组 1 的内容能够在当前位置找到的话,\1 就成功否则失败。记住 Python 字符串也是用反斜杠加数据来允许字符串中包含任意字符的,所以当在 RE 中使用逆向引用时确保使用 raw 字符串。



例如,下面的 RE 在一个字符串中找到成双的词。


#!python

>>> p = re.compile(r'(\b\w+)\s+\1')
>>> p.search('Paris in the the spring').group()
'the the'

象这样只是搜索一个字符串的逆向引用并不常见 -- 用这种方式重复数据的文本格式并不多见 -- 但你不久就可以发现它们用在字符串替换上非常有用。


[编辑] 无捕获组和命名组


精心设计的 REs 也许会用很多组,既可以捕获感兴趣的子串,又可以分组和结构化 RE 本身。在复杂的 REs 里,追踪组号变得困难。有两个功能可以对这个问题有所帮助。它们也都使用正则表达式扩展的通用语法,因此我们来看看第一个。



Perl 5 对标准正则表达式增加了几个附加功能,Python 的 re 模块也支持其中的大部分。选择一个新的单按键元字符或一个以 "\" 开始的特殊序列来表示新的功能,而又不会使 Perl 正则表达式与标准正则表达式产生混乱是有难度的。如果你选择 "&" 做为新的元字符,举个例子,老的表达式认为 "&" 是一个正常的字符,而不会在使用 \& 或 [&] 时也不会转义。



Perl 开发人员的解决方法是使用 (?...) 来做为扩展语法。"?" 在括号后面会直接导致一个语法错误,因为 "?" 没有任何字符可以重复,因此它不会产生任何兼容问题。紧随 "?" 之后的字符指出扩展的用途,因此 (?=foo) 



Python 新增了一个扩展语法到 Perl 扩展语法中。如果在问号后的第一个字符是 "P",你就可以知道它是针对 Python 的扩展。目前有两个这样的扩展: (?P<name>...) 定义一个命名组,(?P=name) 则是对命名组的逆向引用。如果 Perl 5 的未来版本使用不同的语法增加了相同的功能,那么 re 模块也将改变以支持新的语法,这是为了兼容性的目的而保持的 Python 专用语法。



现在我们看一下普通的扩展语法,我们回过头来简化在复杂 REs 中使用组运行的特性。因为组是从左到右编号的,而且一个复杂的表达式也许会使用许多组,它可以使跟踪当前组号变得困难,而修改如此复杂的 RE 是十分麻烦的。在开始时插入一个新组,你可以改变它之后的每个组号。



首先,有时你想用一个组去收集正则表达式的一部分,但又对组的内容不感兴趣。你可以用一个无捕获组: (?:...) 来实现这项功能,这样你可以在括号中发送任何其他正则表达式。


#!python

>>> m = re.match("([abc])+", "abc")
>>> m.groups()
('c',)
>>> m = re.match("(?:[abc])+", "abc")
>>> m.groups()
()

除了捕获匹配组的内容之外,无捕获组与捕获组表现完全一样;你可以在其中放置任何字符,可以用重复元字符如 "*" 来重复它,可以在其他组(无捕获组与捕获组)中嵌套它。(?:...) 对于修改已有组尤其有用,因为你可以不用改变所有其他组号的情况下添加一个新组。捕获组和无捕获组在搜索效率方面也没什么不同,没有哪一个比另一个更快。



其次,更重要和强大的是命名组;与用数字指定组不同的是,它可以用名字来指定。



命令组的语法是 Python 专用扩展之一: (?P<name>...)。名字很明显是组的名字。除了该组有个名字之外,命名组也同捕获组是相同的。`MatchObject` 的方法处理捕获组时接受的要么是表示组号的整数,要么是包含组名的字符串。命名组也可以是数字,所以你可以通过两种方式来得到一个组的信息:


#!python

>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'
>>> m.group(1)
'Lots'

命名组是便于使用的,因为它可以让你使用容易记住的名字来代替不得不记住的数字。这里有一个来自 imaplib 模块的 RE 示例:


#!python

InternalDate = re.compile(r'INTERNALDATE "'
r'(?P<day>[ 123][0-9])-(?P<mon>[A-Z][a-z][a-z])-'
 r'(?P<year>[0-9][0-9][0-9][0-9])'
r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'
r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'
r'"')

很明显,得到 m.group('zonem') 要比记住得到组 9 要容易得多。



因为逆向引用的语法,象 (...)\1 这样的表达式所表示的是组号,这时用组名代替组号自然会有差别。还有一个 Python 扩展:(?P=name) ,它可以使叫 name 的组内容再次在当前位置发现。正则表达式为了找到重复的单词,(\b\w+)\s+\1 也可以被写成 (?P<word>\b\w+)\s+(?P=word):


#!python

>>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
>>> p.search('Paris in the the spring').group()
'the the'

[编辑] 前向界定符


另一个零宽界定符(zero-width assertion)是前向界定符。前向界定符包括前向肯定界定符和后向肯定界定符,所下所示:

(?=...)

前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。

(?!...)

前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功



通过示范在哪前向可以成功有助于具体实现。考虑一个简单的模式用于匹配一个文件名,并将其通过 "." 分成基本名和扩展名两部分。如在 "news.rc" 中,"news" 是基本名,"rc" 是文件的扩展名。



匹配模式非常简单:



.*[.].*$

注意 "." 需要特殊对待,因为它是一个元字符;我把它放在一个字符类中。另外注意后面的 $; 添加这个是为了确保字符串所有的剩余部分必须被包含在扩展名中。这个正则表达式匹配 "foo.bar"、"autoexec.bat"、 "sendmail.cf" 和 "printers.conf"。



现在,考虑把问题变得复杂点;如果你想匹配的扩展名不是 "bat" 的文件名?一些不正确的尝试:



.*[.][^b].*$

上面的第一次去除 "bat" 的尝试是要求扩展名的第一个字符不是 "b"。这是错误的,因为该模式也不能匹配 "foo.bar"。



.*[.]([^b]..|.[^a].|..[^t])$

当你试着修补第一个解决方法而要求匹配下列情况之一时表达式更乱了:扩展名的第一个字符不是 "b"; 第二个字符不是 "a";或第三个字符不是 "t"。这样可以接受 "foo.bar" 而拒绝 "autoexec.bat",但这要求只能是三个字符的扩展名而不接受两个字符的扩展名如 "sendmail.cf"。我们将在努力修补它时再次把该模式变得复杂。



.*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$

在第三次尝试中,第二和第三个字母都变成可选,为的是允许匹配比三个字符更短的扩展名,如 "sendmail.cf"。



该模式现在变得非常复杂,这使它很难读懂。更糟的是,如果问题变化了,你想扩展名不是 "bat" 和 "exe",该模式甚至会变得更复杂和混乱。



前向否定把所有这些裁剪成:



.*[.](?!bat$).*$

前向的意思:如果表达式 bat 在这里没有匹配,尝试模式的其余部分;如果 bat$ 匹配,整个模式将失败。后面的 $ 被要求是为了确保象 "sample.batch" 这样扩展名以 "bat" 开头的会被允许。



将另一个文件扩展名排除在外现在也容易;简单地将其做为可选项放在界定符中。下面的这个模式将以 "bat" 或 "exe" 结尾的文件名排除在外。



.*[.](?!bat$|exe$).*$

[编辑] 修改字符串


到目前为止,我们简单地搜索了一个静态字符串。正则表达式通常也用不同的方式,通过下面的 `RegexObject` 方法,来修改字符串。










方法/属性作用
split()将字符串在 RE 匹配的地方分片并生成一个列表,
sub()找到 RE 匹配的所有子串,并将其用一个不同的字符串替换
subn()与 sub() 相同,但返回新的字符串和替换次数

[编辑] 将字符串分片


`RegexObject` 的 split() 方法在 RE 匹配的地方将字符串分片,将返回列表。它同字符串的 split() 方法相似但提供更多的定界符;split()只支持空白符和固定字符串。就象你预料的那样,也有一个模块级的 re.split() 函数。



split(string [, maxsplit = 0])

通过正则表达式将字符串分片。如果捕获括号在 RE 中使用,那么它们的内容也会作为结果列表的一部分返回。如果 maxsplit 非零,那么最多只能分出 maxsplit 个分片。



你可以通过设置 maxsplit 值来限制分片数。当 maxsplit 非零时,最多只能有 maxsplit 个分片,字符串的其余部分被做为列表的最后部分返回。在下面的例子中,定界符可以是非数字字母字符的任意序列。


#!python

>>> p = re.compile(r'\W+')
>>> p.split('This is a test, short and sweet, of split().')
['This', 'is', 'a', 'test', 'short', 'and', 'sweet', 'of', 'split', '']
>>> p.split('This is a test, short and sweet, of split().', 3)
['This', 'is', 'a', 'test, short and sweet, of split().']

有时,你不仅对定界符之间的文本感兴趣,也需要知道定界符是什么。如果捕获括号在 RE 中使用,那么它们的值也会当作列表的一部分返回。比较下面的调用:


#!python

>>> p = re.compile(r'\W+')
>>> p2 = re.compile(r'(\W+)')
>>> p.split('This... is a test.')
['This', 'is', 'a', 'test', '']
>>> p2.split('This... is a test.')
['This', '... ', 'is', ' ', 'a', ' ', 'test', '.', '']

模块级函数 re.split() 将 RE 作为第一个参数,其他一样。


#!python

>>> re.split('[\W]+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('([\W]+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('[\W]+', 'Words, words, words.', 1)
['Words', 'words, words.']

[编辑] 搜索和替换


其他常见的用途就是找到所有模式匹配的字符串并用不同的字符串来替换它们。sub() 方法提供一个替换值,可以是字符串或一个函数,和一个要被处理的字符串。



sub(replacement, string[, count = 0])

返回的字符串是在字符串中用 RE 最左边不重复的匹配来替换。如果模式没有发现,字符将被没有改变地返回。



可选参数 count 是模式匹配后替换的最大次数;count 必须是非负整数。缺省值是 0 表示替换所有的匹配。



这里有个使用 sub() 方法的简单例子。它用单词 "colour" 替换颜色名。


#!python

>>> p = re.compile( '(blue|white|red)')
>>> p.sub( 'colour', 'blue socks and red shoes')
'colour socks and colour shoes'
>>> p.sub( 'colour', 'blue socks and red shoes', count=1)
'colour socks and red shoes'

subn() 方法作用一样,但返回的是包含新字符串和替换执行次数的两元组。


#!python

>>> p = re.compile( '(blue|white|red)')
>>> p.subn( 'colour', 'blue socks and red shoes')
('colour socks and colour shoes', 2)
>>> p.subn( 'colour', 'no colours at all')
('no colours at all', 0)

空匹配只有在它们没有紧挨着前一个匹配时才会被替换掉。


#!python

>>> p = re.compile('x*')
>>> p.sub('-', 'abxd')
'-a-b-d-'

如果替换的是一个字符串,任何在其中的反斜杠都会被处理。"\n" 将会被转换成一个换行符,"\r"转换成回车等等。未知的转义如 "\j" 则保持原样。逆向引用,如 "\6",被 RE 中相应的组匹配而被子串替换。这使你可以在替换后的字符串中插入原始文本的一部分。



这个例子匹配被 "{" 和 "}" 括起来的单词 "section",并将 "section" 替换成 "subsection"。


#!python

>>> p = re.compile('section{ ( [^}]* ) }', re.VERBOSE)
>>> p.sub(r'subsection{\1}','section{First} section{second}')
'subsection{First} subsection{second}'

还可以指定用 (?P<name>...) 语法定义的命名组。"\g<name>" 将通过组名 "name" 用子串来匹配,并且 "\g<number>" 使用相应的组号。所以 "\g<2>" 等于 "\2",但能在替换字符串里含义不清,如 "\g<2>0"。("\20" 被解释成对组 20 的引用,而不是对后面跟着一个字母 "0" 的组 2 的引用。)


#!python

>>> p = re.compile('section{ (?P<name> [^}]* ) }', re.VERBOSE)
>>> p.sub(r'subsection{\1}','section{First}')
'subsection{First}'
>>> p.sub(r'subsection{\g<1>}','section{First}')
'subsection{First}'
>>> p.sub(r'subsection{\g<name>}','section{First}')
'subsection{First}'

替换也可以是一个甚至给你更多控制的函数。如果替换是个函数,该函数将会被模式中每一个不重复的匹配所调用。在每个调用时,函数被作为 `MatchObject` 的匹配函属,并可以使用这个信息去计算预期的字符串并返回它。



在下面的例子里,替换函数将十进制翻译成十六进制:


#!python

>>> def hexrepl( match ):
... "Return the hex string for a decimal number"
... value = int( match.group() )
... return hex(value)
...
>>> p = re.compile(r'\d+')
>>> p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')
'Call 0xffd2 for printing, 0xc000 for user code.'

当使用模块级的 re.sub() 函数时,模式作为第一个参数。模式也许是一个字符串或一个 `RegexObject`;如果你需要指定正则表达式标志,你必须要么使用 `RegexObject` 做第一个参数,或用使用模式内嵌修正器,如 sub("(?i)b+", "x", "bbbb BBBB") returns 'x x'。


[编辑] 常见问题


正则表达式对一些应用程序来说是一个强大的工具,但在有些时候它并不直观而且有时它们不按你期望的运行。本节将指出一些最容易犯的常见错误。


[编辑] 使用字符串方式


有时使用 re 模块是个错误。如果你匹配一个固定的字符串或单个的字符类,并且你没有使用 re 的任何象 IGNORECASE 标志的功能,那么就没有必要使用正则表达式了。字符串有一些方法是对固定字符串进行操作的,它们通常快很多,因为都是一个个经过优化的C 小循环,用以代替大的、更具通用性的正则表达式引擎。



举个用一个固定字符串替换另一个的例子;如,你可以把 "deed" 替换成 "word"。re.sub() seems like the function to use for this, but consider the replace() method. 注意 replace() 也可以在单词里面进行替换,可以把 "swordfish" 变成 "sdeedfish",不过 RE 也是可以做到的。(为了避免替换单词的一部分,模式将写成 \bword\b,这是为了要求 "word" 两边有一个单词边界。这是个超出替换能力的工作)。



另一个常见任务是从一个字符串中删除单个字符或用另一个字符来替代它。你也许可以用象 re.sub('\n',' ',S) 这样来实现,但 translate() 能够实现这两个任务,而且比任何正则表达式操作起来更快。



总之,在使用 re 模块之前,先考虑一下你的问题是否可以用更快、更简单的字符串方法来解决。


[编辑] match() vs search()


match() 函数只检查 RE 是否在字符串开始处匹配,而 search() 则是扫描整个字符串。记住这一区别是重要的。记住,match() 只报告一次成功的匹配,它将从 0 处开始;如果匹配不是从 0 开始的,match() 将不会报告它。


#!python

>>> print re.match('super', 'superstition').span()
(0, 5)
>>> print re.match('super', 'insuperable')
None

另一方面,search() 将扫描整个字符串,并报告它找到的第一个匹配。


#!python

>>> print re.search('super', 'superstition').span()
(0, 5)
>>> print re.search('super', 'insuperable').span()
(2, 7)

有时你可能倾向于使用 re.match(),只在RE的前面部分添加 .* 。请尽量不要这么做,最好采用 re.search() 代替之。正则表达式编译器会对 REs 做一些分析以便可以在查找匹配时提高处理速度。一个那样的分析机会指出匹配的第一个字符是什么;举个例子,模式 Crow 必须从 "C" 开始匹配。分析机可以让引擎快速扫描字符串以找到开始字符,并只在 "C" 被发现后才开始全部匹配。

添加 .* 会使这个优化失败,这就要扫描到字符串尾部,然后回溯以找到 RE 剩余部分的匹配。使用 re.search() 代替。


[编辑] 贪婪 vs 不贪婪


当重复一个正则表达式时,如用 a*,操作结果是尽可能多地匹配模式。当你试着匹配一对对称的定界符,如 HTML 标志中的尖括号时这个事实经常困扰你。匹配单个 HTML 标志的模式不能正常工作,因为 .* 的本质是“贪婪”的


#!python

>>> s = '<html><head><title>Title</title>'
>>> len(s)
32
>>> print re.match('<.*>', s).span()
(0, 32)
>>> print re.match('<.*>', s).group()
<html><head><title>Title</title>

RE 匹配 在 "<html>" 中的 "<",.* 消耗掉子符串的剩余部分。在 RE 中保持更多的左,虽然 > 不能匹配在字符串结尾,因此正则表达式必须一个字符一个字符地回溯,直到它找到 > 的匹配。最终的匹配从 "<html" 中的 "<" 到 "</title>" 中的 ">",这并不是你所想要的结果。



在这种情况下,解决方案是使用不贪婪的限定符 *?、+?、?? 或 {m,n}?,尽可能匹配小的文本。在上面的例子里, ">" 在第一个 "<" 之后被立即尝试,当它失败时,引擎一次增加一个字符,并在每步重试 ">"。这个处理将得到正确的结果:


#!python

>>> print re.match('<.*?>', s).group()
<html>

注意用正则表达式分析 HTML 或 XML 是痛苦的。变化混乱的模式将处理常见情况,但 HTML 和 XML 则是明显会打破正则表达式的特殊情况;当你编写一个正则表达式去处理所有可能的情况时,模式将变得非常复杂。象这样的任务用 HTML 或 XML 解析器。


[编辑] 不用 re.VERBOSE


现在你可能注意到正则表达式的表示是十分紧凑,但它们非常不好读。中度复杂的 REs 可以变成反斜杠、圆括号和元字符的长长集合,以致于使它们很难读懂。



在这些 REs 中,当编译正则表达式时指定 re.VERBOSE 标志是有帮助的,因为它允许你可以编辑正则表达式的格式使之更清楚。



re.VERBOSE 标志有这么几个作用。在正则表达式中不在字符类中的空白符被忽略。这就意味着象 dog | cat 这样的表达式和可读性差的 dog|cat 相同,但 [a b] 将匹配字符 "a"、"b" 或 空格。另外,你也可以把注释放到 RE 中;注释是从 "#" 到下一行。当使用三引号字符串时,可以使 REs 格式更加干净:


#!python

pat = re.compile(r"""
\s* # Skip leading whitespace
(?P<header>[^:]+) # Header name
\s* : # Whitespace, and a colon
(?P<value>.*?) # The header's value -- *? used to
# lose the following trailing whitespace
\s*$ # Trailing whitespace to end-of-line
""", re.VERBOSE)

这个要难读得多:


#!python

pat = re.compile(r"\s*(?P<header>[^:]+)\s*:(?P<value>.*?)\s*$")

[编辑] 反馈


正则表达式是一个复杂的主题。本文能否有助于你理解呢?那些部分是否不清晰,或在这儿没有找到你所遇到的问题?如果是那样的话,请将建议发给作者以便改进。

描述正则表达式最全面的书非Jeffrey Friedl 写的《精通正则表达式》莫属,该书由O'Reilly 出版。可惜该书只专注于 Perl 和 Java 风格的正则表达式,不含任何 Python 材料,所以不足以用作Python编程时的参考。(第一版包含有 Python 现已过时的 regex 模块,自然用处不大)。

《精通正则表达式》第三版已经有部分正则表达式使用python说明,另外PHP风格的更是独立一个章节说明。--why