#
From:http://martybugs.net/articles/print.cgi
Web Page Printability With CSS
author: Martin
"mpot" Pot
date: 7 January 2005
Introduction
This article describes how to use CSS media types to make your website
much more
printer-friendly.
An overview of CSS media types is given, and sample HTML and CSS code is
provided,
detailing how to implement CSS media types for improving printability.
Why?
Most webpages do not print very well, with large amounts of the printed
page being wasted with
banners, navigation menus, advertising, and other unnecessary content.
When attempting to print out the main text of a webpage, you often have
to resort to
copying the text into Word or another editor, and then printing it.
Some websites make use of a link at the bottom of the page, linking to a
"printable version"
of the same page. However, this requires additional effort on the part
of the web developer.
There is a much easier way to make your pages print better, and that's
via the use of
CSS media types.
For example, all content on
MartyBugs.Net
has been designed to be
printer-friendly.
When printing pages from this site
using a modern browser, elements such as the left menu column and the
right column (where used)
will be hidden, thus ensuring there's more room on the printed page for
the main content.
|
page as displayed on a 1024x768 screen
|
The image above shows how one of the pages on this website would be
displayed on a
computer screen, at a resolution of 1024x768.
|
|
|
printed page,
no print optimisation
|
|
printed page,
optimised for printing
|
The left image above shows how the same page will look when printed, if
all the page content is printed.
Notice how little room there is in the centre of the page for the main
content.
The right image above shows the same page, but the navigation and other
content on the left and right
hand sides of the page is not printed. CSS media types have been used
to hide this content when
the page is printed.
CSS Media Types
The primary aim of the CSS media types is to allow the web-page author
to define different styles for
a page, depending on the media being used to display the page.
CSS 2.1 supports numerous media types, including
all (suitable for all devices),
screen (computer screens),
print (pages viewed on-screen in print-preview mode and printed
pages).
Other less-common media types are also supported, such as braille,
embossed, handheld, projection,
speech, etc, but we won't be discussing any of these.
CSS media types are defined using the rule in
your CSS style-sheet,
or in your in-line CSS style definitions.
For example, to define different font sizes for the
print
and
screen media types, as well as a common
line-height to be used for both,
the CSS definition is as follows:
@media print {
body { font-size: 10pt }
}
@media screen {
body { font-size: 13px }
}
@media screen, print {
body { line-height: 1.2 }
}
The CSS media types allow you to specify different CSS properties for
any element, so it will be
displayed differently on the screen than when printed.
For the purposes of this article, the only thing we're interested in is
to hide some page elements
when the page is printed.
Refer to the
W3C CSS
2.1 Media Definitions
for more details on CSS media types.
Using CSS Media Types
The web pages on this website are all generated on-the-fly, using
server-side Perl templates.
All pages have a number of common elements, namely:
- a banner across the top
- navigation menu on the left side
- main content in the centre
- advertising and other content on the right side
- footer across the bottom
When someone prints out a page from this website, CSS media types are
used to hide a number
of elements on the page, including the navigation menu, advertising, and
the navigation content
in the footer.
To provide a working demonstration of how CSS media types can be used in
this way, a demonstration
web page was coded, using tables to define the banner area across the
top of the page, with
a column down the left-hand side for the navigation menu, a column down
the right-hand side
for other content, and a footer across the bottom of the page.
This layout is one of the most commonly used page layouts on the
internet at the present - hence
my choice to use it as an example.
the example page
Firstly, we define the CSS styles for the page:
<style type="text/css">
@media print {
.noprint { display: none; }
}
</style>
Note that the CSS styles can also be defined using a separate CSS file,
but example page has the CSS
defined in-line for simplicity (and to keep the example to a single
file).
The above CSS definition is defining a style called
noprint,
and will only
be applied to printed content. Setting the
display
property to
none means any content using this CSS style
will not be displayed
when printed, but will be displayed for all other media types.
There are a number of components on this page that we don't want
printed, namely the columns on the
left-hand side and on the right-hand side.
The
noprint style is applied to the table
cells holding this content,
thus ensuring they won't be visible when the page is printed.
<table border='1' cellpadding='4' cellspacing='0' width='100%' >
<tr height='60'><td colspan='3'>
banner place-holder
</td></tr>
<tr><td width='150' valign='top' class='noprint'>
left-side content place-holder
</td><td>
<b>main content</b>
[snip!]
</td><td width='150' valign='top' class='noprint'>
right-side content place-holder
</td></tr><tr><td colspan='3'>
footer content place-holder
</td></tr>
</table>
This will result in the columns on the left and right-hand sides being
hidden when the page
is printed, thus providing more space on the printed page for the
content itself.
Note that this style needs to be applied to the table cells themselves,
and not just to the content
in these table cells, else the (empty) cells will still show up on the
printed copy.
Testing Your CSS
The easiest way to test CSS styles for print media is to use a web
browser which has print preview
capabilities.
The print preview will give you a fairly accurate representation of how
the page will look
when it is printed, and is a much more efficient way to test your media
styles, rather than
actually printing out pages on a printer.
Most popular web browsers should support print preview functionality.
The
FireFox
browser has print preview functionality, although it lacks any
zoom/unzoom capabilities.
As an alternative to using print preview, you can print the web page to a
PDF file.
There are numerous (costly, freeware, and anywhere in between) software
packages for
doing this.
I recommend using the freeware and open-source
PDFCreator,
which is
a Windows printer driver which allows you to create PDFs from any
Windows application, just by
selecting the PDFCreator driver as the virtual printer from that
application.
Also be sure to use the
W3C's
free
CSS
Validation Service to
check your CSS definitions.
References
http://support.microsoft.com/kb/973904
Let me fix it myself
To unregister the mswrd632 converter yourself, edit the registry as follows:
- Click Start, click Run, type regedit, and then click OK.
- Locate and then click the following registry subkey:
- For 32-bit versions of Windows:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Text Converters\Import\MSWord6.wpc
- For 64-bit versions of Windows:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Shared Tools\Text Converters\Import\MSWord6.wpc
- On the Edit menu, click Delete.
- Click Yes.
- Exit Registry Editor.
This change will effectively unregister the converter and disable it for third-party applications and for Microsoft Office. Microsoft Office will use its own text converters to open these kinds of files.
The user was running Office 2007 and getting this error. After doing some research, we came across a few possible solutions. In this post, I’ll list them out here.
Method 1 – Unregister Text Converter
Basically, in Windows XP SP2 and above and Windows Server 2003 SP1 and above, if you have a plain text file or another kind of file that is not a Microsoft Word file, but has a .doc extension, you will get this error.
This can also happen if you are opening a really old document created by Word for Windows 6.0 or Word 97 documents. In this case, you can disable the mswrd632 converter so you don’t get this error. The files will then be opened by the Microsoft Office text converters.
You can unregister this converter by going to Start, then run and typing regedit. Then navigate to the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Text Converters\Import\MSWord6.wpc
Right-click on the MSWord6.wpc key in the left hand pane and choose Delete. If you have a Word 97 document, you should still be able to open it in Word 2003 or 2007. However, you will not be able to open these files in WordPad anymore. You’ll get an error like:
Cannot load Word for Windows 6.0 files
If you really have to use WordPad to open Word 6.0/95 files, you can re-enable the Word 6.0/95 for Windows and Macintosh to RFT converter. Open the registry and go to the following keys:
For 32-bit versions of Windows
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\ Applets\Wordpad
For Microsoft Windows on Windows 64 (WOW) mode
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\ CurrentVersion\Applets\Wordpad
If the Wordpad key is not there in the left-hand pane, create it. After that, create a new DWORD value in the right-pane called AllowConversion and give it a value of 1.
Method 2 – Copy the MSWrd632.wpc File
The other way to solve this issue is to copy the MSWrd632.wpc file from another computer to the computer having problems.
The only issue with this is that it is less secure and makes your computer vulnerable to a possible security hack, so don’t do this unless you really have to or that computer is not connected to the Internet.
You can usually find this file in the following path:
C:\Program Files\Common Files\Microsoft Shared\TextConv\
That’s about it! If you are still having this problem, post a comment here and I’ll try to help! Enjoy!
详解COM Add In的LoadBehavior及其妙用
http://blog.csdn.net/v_jzho/archive/2007/10/06/1813080.aspx
基于Visual Studio 2003/2005的Office插件开发FAQ
http://blog.csdn.net/tonyqus/archive/2007/02/24/1513256.aspx
There are several ways to deploy an assembly into the global assembly
cache:
1) Use an installer designed to work with the global assembly cache. This
is the preferred option for installing assemblies into the global assembly
cache
2) Use a developer tool called the Global Assembly Cache tool (Gacutil.exe)
provided by the .NET Framework SDK.
3) Use Windows Explorer to drag and drop assemblies into the cache.
4) use install shield. (注意:installshield里只有msi等几个类型的项目支持这个)
From:http://bytes.com/topic/net/answers/109942-deploy-assembly-gac
http://www.microsoft.com/downloads/details.aspx?familyid=59DAEBAA-BED4-4282-A28C-B864D8BFA513&displaylang=en
http://msdn.microsoft.com/en-us/library/15s06t57(VS.80).aspx
The 'AllOtherFiles' is an entry automatically created when you check the GlobalAssemblyCache predefined folder. After you add in your file(s), perform the following steps:
1. Right-click "Destination Computer"
2. Check "Show Components"
3. Expand the [GlobalAssemblyCache] tree.
4. Delete the "AllOtherFiles" entry.
正则表达式(regular expression)
关键字:
正则表达式,Regular Expression
作者:笑容
发表于:2004年05月03日
最后更新:2005年01月17日
19:54
版权声明:使用创作公用版权协议
引用地址:<a
href="http://oo8h.51.net/docs/regular_expression.htm">正则表达式(regular
expression)</a>
NAV: 笑容的八小时外 / 笑容的八小时外资料索引
如何创建一个网站 (HOW TO:
Initiate a website) Red Hat Enterprise
Linux 介绍
前言
正则表达式是烦琐的,但是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感。只要认真去阅读这些资料,加上应用的时候进行一定的参考,掌握正则表达式不是问题。
索引
1._引子
2._正则表达式的历史
3._正则表达式定义
3.1_普通字符
3.2_非打印字符
3.3_特殊字符
3.4_限定符
3.5_定位符
3.6_选择
3.7_后向引用
4._各种操作符的运算优先级
5._全部符号解释
6._部分例子
7._正则表达式匹配规则
7.1_基本模式匹配
7.2_字符簇
7.3_确定重复出现
目前,正则表达式已经在很多软件中得到广泛的应用,包括*nix(Linux,
Unix等),HP等操作系统,PHP,C#,Java等开发环境,以及很多的应用软件中,都可以看到正则表达式的影子。
正则表达式的使用,可以通过简单的办法来实现强大的功能。为了简单有效而又不失强大,造成了正则表达式代码的难度较大,学习起来也不是很容易,所以需要付出一些努力才行,入门之后参照一定的参考,使用起来还是比较简单有效的。
例子: ^.+@.+""..+$
这样的代码曾经多次把我自己给吓退过。可能很多人也是被这样的代码给吓跑的吧。继续阅读本文将让你也可以自由应用这样的代码。
注意:这里的第7部分跟前面的内容看起来似乎有些重复,目的是把前面表格里的部分重新描述了一次,目的是让这些内容更容易理解。
正则表达式的“祖先”可以一直上溯至对人类神经系统如何工作的早期研究。Warren
McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。
1956 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts
早期工作的基础上,发表了一篇标题为“神经网事件的表示法”的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集的代数”的表达式,因此采用“正则表达式”这个术语。
随后,发现可以将这一工作应用于使用 Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson 是 Unix
的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的 qed 编辑器。
如他们所说,剩下的就是众所周知的历史了。从那时起直至现在正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。
正则表达式(regular
expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。
- 列目录时, dir *.txt或ls
*.txt中的*.txt就不是一个正则表达式,因为这里*与正则式的*的含义是不同的。
正则表达式是由普通字符(例如字符 a 到
z)以及特殊字符(称为元字符)组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符,所有数字,所有标点符号以及一些符号。
字符 |
含义 |
"cx |
匹配由x指明的控制字符。例如, "cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z
或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
"f |
匹配一个换页符。等价于 "x0c 和 "cL。 |
"n |
匹配一个换行符。等价于 "x0a 和 "cJ。 |
"r |
匹配一个回车符。等价于 "x0d 和 "cM。 |
"s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ "f"n"r"t"v]。 |
"S |
匹配任何非空白字符。等价于 [^ "f"n"r"t"v]。 |
"t |
匹配一个制表符。等价于 "x09 和 "cI。 |
"v |
匹配一个垂直制表符。等价于 "x0b 和
"cK。 |
所谓特殊字符,就是一些有特殊含义的字符,如上面说的"*.txt"中的*,简单的说就是表示任何字符串的意思。如果要查找文件名中有*的文件,则需要对*进行转义,即在其前加一个"。ls
"*.txt。正则表达式有以下特殊字符。
特别字符 |
说明 |
$ |
匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配
'"n' 或 '"r'。要匹配 $ 字符本身,请使用 "$。 |
( ) |
标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 "( 和
")。 |
* |
匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 "*。 |
+ |
匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 "+。 |
. |
匹配除换行符 "n之外的任何单字符。要匹配 .,请使用 "。 |
[ |
标记一个中括号表达式的开始。要匹配 [,请使用 "[。 |
? |
匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用
"?。 |
" |
将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, 'n' 匹配字符
'n'。'"n' 匹配换行符。序列 '""' 匹配 """,而 '"(' 则匹配 "("。 |
^ |
匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^
字符本身,请使用 "^。 |
{ |
标记限定符表达式的开始。要匹配 {,请使用 "{。 |
| |
指明两项之间的一个选择。要匹配 |,请使用 "|。 |
- 构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与操作符将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有*或+或?或{n}或{n,}或{n,m}共6种。
*、+和?限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。
正则表达式的限定符有:
字符 |
描述 |
* |
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。*
等价于{0,}。 |
+ |
匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配
"z"。+ 等价于 {1,}。 |
? |
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does"
中的"do" 。? 等价于 {0,1}。 |
{n} |
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的
'o',但是能匹配 "food" 中的两个 o。 |
{n,} |
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配
"foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} |
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m
次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于
'o?'。请注意在逗号和两个数之间不能有空格。 |
用来描述字符串或单词的边界,^和$分别指字符串的开始与结束,"b描述单词的前或后边界,"B表示非单词边界。
不能对定位符使用限定符。
用圆括号将所有选择项括起来,相邻的选择项之间用|分隔。但用圆括号会有一个副作用,是相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用。
其中?:是非捕获元之一,还有两个非捕获元是?=和?!,这两个还有更多的含义,前者为正向预查,在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串,后者为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。
对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从
1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '"n' 访问,其中 n
为一个标识特定缓冲区的一位或两位十进制数。
可以使用非捕获元字符 '?:', '?=', or '?!' 来忽略对相关匹配的保存。
相同优先级的从左到右进行运算,不同优先级的运算先高后低。各种操作符的优先级从高到低如下:
操作符 |
描述 |
" |
转义符 |
(), (?:), (?=), [] |
圆括号和方括号 |
*, +, ?, {n}, {n,}, {n,m} |
限定符 |
^, $, "anymetacharacter |
位置和顺序 |
| |
“或”操作 |
字符 |
描述 |
" |
将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n'
匹配字符 "n"。'"n' 匹配一个换行符。序列 '""' 匹配 """ 而 ""(" 则匹配 "("。 |
^ |
匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配
'"n' 或 '"r' 之后的位置。 |
$ |
匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '"n'
或 '"r' 之前的位置。 |
* |
匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。*
等价于{0,}。 |
+ |
匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配
"z"。+ 等价于 {1,}。 |
? |
匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does"
中的"do" 。? 等价于 {0,1}。 |
{n} |
n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的
'o',但是能匹配 "food" 中的两个 o。 |
{n,} |
n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配
"foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。 |
{n,m} |
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m
次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于
'o?'。请注意在逗号和两个数之间不能有空格。 |
? |
当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m})
后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?'
将匹配单个 "o",而 'o+' 将匹配所有 'o'。 |
. |
匹配除 ""n" 之外的任何单个字符。要匹配包括 '"n' 在内的任何字符,请使用象 '[."n]'
的模式。 |
(pattern) |
匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches
集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 '"(' 或
'")'。 |
(?:pattern) |
匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用
"或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries'
更简略的表达式。 |
(?=pattern) |
正向预查,在任何匹配 pattern
的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配
"Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的
"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) |
负向预查,在任何不匹配 pattern
的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配
"Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的
"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始 |
x|y |
匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配
"zood" 或 "food"。 |
[xyz] |
字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的
'a'。 |
[^xyz] |
负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain"
中的'p'。 |
[a-z] |
字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z'
范围内的任意小写字母字符。 |
[^a-z] |
负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到
'z' 范围内的任意字符。 |
"b |
匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er"b' 可以匹配"never" 中的
'er',但不能匹配 "verb" 中的 'er'。 |
"B |
匹配非单词边界。'er"B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的
'er'。 |
"cx |
匹配由 x 指明的控制字符。例如, "cM 匹配一个 Control-M 或回车符。x 的值必须为
A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
"d |
匹配一个数字字符。等价于 [0-9]。 |
"D |
匹配一个非数字字符。等价于 [^0-9]。 |
"f |
匹配一个换页符。等价于 "x0c 和 "cL。 |
"n |
匹配一个换行符。等价于 "x0a 和 "cJ。 |
"r |
匹配一个回车符。等价于 "x0d 和 "cM。 |
"s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ "f"n"r"t"v]。 |
"S |
匹配任何非空白字符。等价于 [^ "f"n"r"t"v]。 |
"t |
匹配一个制表符。等价于 "x09 和 "cI。 |
"v |
匹配一个垂直制表符。等价于 "x0b 和 "cK。 |
"w |
匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
"W |
匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
"xn |
匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'"x41' 匹配
"A"。'"x041' 则等价于 '"x04' & "1"。正则表达式中可以使用 ASCII 编码。. |
"num |
匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)"1'
匹配两个连续的相同字符。 |
"n |
标识一个八进制转义值或一个向后引用。如果 "n 之前至少 n 个获取的子表达式,则 n
为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。 |
"nm |
标识一个八进制转义值或一个向后引用。如果 "nm 之前至少有 nm 个获得子表达式,则 nm
为向后引用。如果 "nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则
"nm 将匹配八进制转义值 nm。 |
"nml |
如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值
nml。 |
"un |
匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, "u00A9
匹配版权符号 (?)。 |
正则表达式 |
说明 |
/"b([a-z]+) "1"b/gi |
一个单词连续出现的位置 |
/("w+):"/"/([^/:]+)(:"d*)?([^# ]*)/ |
将一个URL解析为协议、域、端口及相对路径 |
/^(?:Chapter|Section) [1-9][0-9]{0,1}$/ |
定位章节的位置 |
/[-a-z]/ |
A至z共26个字母再加一个-号。 |
/ter"b/ |
可匹配chapter,而不能terminal |
/"Bapt/ |
可匹配chapter,而不能aptitude |
/Windows(?=95 |98 |NT )/ |
可匹配Windows95或Windows98或WindowsNT,当找到一个匹配后,从Windows后面开始进行下一次的检索匹配。 |
7.1
基本模式匹配
一切从最基本的开始。模式,是正规表达式最基本的元素,它们是一组描述字符串特征的字符。模式可以很简单,由普通的字符串组成,也可以非常复杂,往往用特殊的字符表示一个范围内的字符、重复出现,或表示上下文。例如:
^once
这个模式包含一个特殊的字符^,表示该模式只匹配那些以once开头的字符串。例如该模式与字符串"once upon a time"匹配,与"There
once was a man from NewYork"不匹配。正如如^符号表示开头一样,$符号用来匹配那些以给定模式结尾的字符串。
bucket$
这个模式与"Who kept all of this cash in a
bucket"匹配,与"buckets"不匹配。字符^和$同时使用时,表示精确匹配(字符串与模式一样)。例如:
^bucket$
只匹配字符串"bucket"。如果一个模式不包括^和$,那么它与任何包含该模式的字符串匹配。例如:模式
once
与字符串
There once was a man from NewYork
Who kept all of his cash in a
bucket.
是匹配的。
在该模式中的字母(o-n-c-e)是字面的字符,也就是说,他们表示该字母本身,数字也是一样的。其他一些稍微复杂的字符,如标点符号和白字符(空格、制表符等),要用到转义序列。所有的转义序列都用反斜杠(")打头。制表符的转义序列是:"t。所以如果我们要检测一个字符串是否以制表符开头,可以用这个模式:
^"t
类似的,用"n表示“新行”,"r表示回车。其他的特殊符号,可以用在前面加上反斜杠,如反斜杠本身用""表示,句号.用".表示,以此类推。
7.2
字符簇
在INTERNET的程序中,正规表达式通常用来验证用户的输入。当用户提交一个FORM以后,要判断输入的电话号码、地址、EMAIL地址、信用卡号码等是否有效,用普通的基于字面的字符是不够的。
所以要用一种更自由的描述我们要的模式的办法,它就是字符簇。要建立一个表示所有元音字符的字符簇,就把所有的元音字符放在一个方括号里:
[AaEeIiOoUu]
这个模式与任何元音字符匹配,但只能表示一个字符。用连字号可以表示一个字符的范围,如:
[a-z] //匹配所有的小写字母
[A-Z] //匹配所有的大写字母
[a-zA-Z] //匹配所有的字母
[0-9]
//匹配所有的数字
[0-9"."-] //匹配所有的数字,句号和减号
[ "f"r"t"n] //匹配所有的白字符
同样的,这些也只表示一个字符,这是一个非常重要的。如果要匹配一个由一个小写字母和一位数字组成的字符串,比如"z2"、"t6"或"g7",但不是"ab2"、"r2d3"
或"b52"的话,用这个模式:
^[a-z][0-9]$
尽管[a-z]代表26个字母的范围,但在这里它只能与第一个字符是小写字母的字符串匹配。
前面曾经提到^表示字符串的开头,但它还有另外一个含义。当在一组方括号里使用^是,它表示“非”或“排除”的意思,常常用来剔除某个字符。还用前面的例子,我们要求第一个字符不能是数字:
^[^0-9][0-9]$
这个模式与"&5"、"g7"及"-2"是匹配的,但与"12"、"66"是不匹配的。下面是几个排除特定字符的例子:
[^a-z] //除了小写字母以外的所有字符
[^"""/"^] //除了(")(/)(^)之外的所有字符
[^"""']
//除了双引号(")和单引号(')之外的所有字符
特殊字符"."
(点,句号)在正规表达式中用来表示除了“新行”之外的所有字符。所以模式"^.5$"与任何两个字符的、以数字5结尾和以其他非“新行”字符开头的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一个“新行”的字符串。
PHP的正规表达式有一些内置的通用字符簇,列表如下:
字符簇 含义
[[:alpha:]] 任何字母
[[:digit:]] 任何数字
[[:alnum:]] 任何字母和数字
[[:space:]] 任何白字符
[[:upper:]] 任何大写字母
[[:lower:]] 任何小写字母
[[:punct:]] 任何标点符号
[[:xdigit:]] 任何16进制的数字,相当于[0-9a-fA-F]
7.3
确定重复出现
到现在为止,你已经知道如何去匹配一个字母或数字,但更多的情况下,可能要匹配一个单词或一组数字。一个单词有若干个字母组成,一组数字有若干个单数组成。跟在字符或字符簇后面的花括号({})用来确定前面的内容的重复出现的次数。
字符簇 含义
^[a-zA-Z_]$ 所有的字母和下划线
^[[:alpha:]]{3}$ 所有的3个字母的单词
^a$ 字母a
^a{4}$ aaaa
^a{2,4}$ aa,aaa或aaaa
^a{1,3}$ a,aa或aaa
^a{2,}$
包含多于两个a的字符串
^a{2,} 如:aardvark和aaab,但apple不行
a{2,}
如:baad和aaa,但Nantucket不行
"t{2} 两个制表符
.{2} 所有的两个字符
这些例子描述了花括号的三种不同的用法。一个数字,{x}的意思是“前面的字符或字符簇只出现x次”;一个数字加逗号,{x,}的意思是“前面的内容出现x或更多的次数”;两个用逗号分隔的数字,{x,y}表示“前面的内容至少出现x次,但不超过y次”。我们可以把模式扩展到更多的单词或数字:
^[a-zA-Z0-9_]{1,}$ //所有包含一个以上的字母、数字或下划线的字符串
^[0-9]{1,}$ //所有的正数
^"-{0,1}[0-9]{1,}$ //所有的整数
^"-{0,1}[0-9]{0,}".{0,1}[0-9]{0,}$ //所有的小数
最后一个例子不太好理解,是吗?这么看吧:与所有以一个可选的负号("-{0,1})开头(^)、跟着0个或更多的数字([0-9]{0,})、和一个可选的小数点(".{0,1})再跟上0个或多个数字([0-9]{0,}),并且没有其他任何东西($)。下面你将知道能够使用的更为简单的方法。
特殊字符"?"与{0,1}是相等的,它们都代表着:“0个或1个前面的内容”或“前面的内容是可选的”。所以刚才的例子可以简化为:
^"-?[0-9]{0,}".?[0-9]{0,}$
特殊字符"*"与{0,}是相等的,它们都代表着“0个或多个前面的内容”。最后,字符"+"与
{1,}是相等的,表示“1个或多个前面的内容”,所以上面的4个例子可以写成:
^[a-zA-Z0-9_]+$ //所有包含一个以上的字母、数字或下划线的字符串
^[0-9]+$ //所有的正数
^"-?[0-9]+$
//所有的整数
^"-?[0-9]*".?[0-9]*$ //所有的小数
当然这并不能从技术上降低正规表达式的复杂性,但可以使它们更容易阅读。
参考文献:
JScript 和 VBScript 正则表达式
微软MSDN上的例子(英文):
- Scanning for HREFS
- Provides an example that searches an input string and prints
out all the href="..." values and their locations in the string.
- Changing Date Formats
- Provides an example that replaces dates of the form mm/dd/yy
with dates of the form dd-mm-yy.
- Extracting URL Information
- Provides an example that extracts a protocol and port number
from a string containing a URL. For example,
"http://www.contoso.com:8080/letters/readme.html" returns "http:8080".
- Cleaning an Input String
- provides an example that strips invalid non-alphanumeric
characters from a string.
- Confirming Valid E-Mail Format
- Provides an example that you can use to verify that a string is
in valid e-mail format
|
正则表达式(regular
expression)对象包含一个正则表达式模式(pattern)。它具有用正则表达式模式去匹配或代替一个串(string)中特定字符(或字符集合)的属性(properties)和方法(methods)。
要为一个单独的正则表达式添加属性,可以使用正则表达式构造函数(constructor
function),无论何时被调用的预设置的正则表达式拥有静态的属性(the predefined RegExp object has static
properties that are set whenever any regular expression is used,
我不知道我翻得对不对,将原文列出,请自行翻译)。
- 创建:
一个文本格式或正则表达式构造函数
文本格式: /pattern/flags
正则表达式构造函数: new
RegExp("pattern"[,"flags"]);
- 参数说明:
pattern -- 一个正则表达式文本
flags -- 如果存在,将是以下值:
g: 全局匹配
i:
忽略大小写
gi: 以上组合
[注意] 文本格式的参数不用引号,而在用构造函数时的参数需要引号。如:/ab+c/i new
RegExp("ab+c","i")是实现一样的功能。在构造函数中,一些特殊字符需要进行转意(在特殊字符前加""")。如:re = new
RegExp("""w+")
正则表达式中的特殊字符
字符 |
含意 |
" |
做为转意,即通常在"""后面的字符不按原来意义解释,如/b/匹配字符"b",当b前面加了反斜杆后/"b/,转意为匹配一个单词的边界。
-或-
对正则表达式功能字符的还原,如"*"匹配它前面元字符0次或多次,/a*/将匹配a,aa,aaa,加了"""后,/a"*/将只匹配"a*"。
|
^ |
匹配一个输入或一行的开头,/^a/匹配"an A",而不匹配"An a" |
$ |
匹配一个输入或一行的结尾,/a$/匹配"An a",而不匹配"an A" |
* |
匹配前面元字符0次或多次,/ba*/将匹配b,ba,baa,baaa |
+ |
匹配前面元字符1次或多次,/ba*/将匹配ba,baa,baaa |
? |
匹配前面元字符0次或1次,/ba*/将匹配b,ba |
(x) |
匹配x保存x在名为$1...$9的变量中 |
x|y |
匹配x或y |
{n} |
精确匹配n次 |
{n,} |
匹配n次以上 |
{n,m} |
匹配n-m次 |
[xyz] |
字符集(character set),匹配这个集合中的任一一个字符(或元字符) |
[^xyz] |
不匹配这个集合中的任何一个字符 |
["b] |
匹配一个退格符 |
"b |
匹配一个单词的边界 |
"B |
匹配一个单词的非边界 |
"cX |
这儿,X是一个控制符,/"cM/匹配Ctrl-M |
"d |
匹配一个字数字符,/"d/ = /[0-9]/ |
"D |
匹配一个非字数字符,/"D/ = /[^0-9]/ |
"n |
匹配一个换行符 |
"r |
匹配一个回车符 |
"s |
匹配一个空白字符,包括"n,"r,"f,"t,"v等 |
"S |
匹配一个非空白字符,等于/[^"n"f"r"t"v]/ |
"t |
匹配一个制表符 |
"v |
匹配一个重直制表符 |
"w |
匹配一个可以组成单词的字符(alphanumeric,这是我的意译,含数字),包括下划线,如["w]匹配"$5.98"中的5,等于[a-zA-Z0-9]
|
"W |
匹配一个不可以组成单词的字符,如["W]匹配"$5.98"中的$,等于[^a-zA-Z0-9]。 |
|
说了这么多了,我们来看一些正则表达式的实际应用的例子:
E-mail地址验证:
function test_email(strEmail) {
var myReg =
/^[_a-z0-9]+@([_a-z0-9]+".)+[a-z0-9]{2,3}$/;
if(myReg.test(strEmail))
return true;
return false;
}
HTML代码的屏蔽
function
mask_HTMLCode(strInput) {
var myReg = /<("w+)>/;
return
strInput.replace(myReg, "<$1>");
}
正则表达式对象的属性及方法
预定义的正则表达式拥有有以下静态属性:input, multiline,
lastMatch, lastParen, leftContext,
rightContext和$1到$9。其中input和multiline可以预设置。其他属性的值在执行过exec或test方法后被根据不同条件赋以不同的值。许多属性同时拥有长和短(perl风格)的两个名字,并且,这两个名字指向同一个值。(JavaScript模拟perl的正则表达式)
正则表达式对象的属性
属性 |
含义 |
$1...$9 |
如果它(们)存在,是匹配到的子串 |
$_ |
参见input |
$* |
参见multiline |
$& |
参见lastMatch |
$+ |
参见lastParen |
$` |
参见leftContext |
$' |
参见rightContext |
constructor |
创建一个对象的一个特殊的函数原型 |
global |
是否在整个串中匹配(bool型) |
ignoreCase |
匹配时是否忽略大小写(bool型) |
input |
被匹配的串 |
lastIndex |
最后一次匹配的索引 |
lastParen |
最后一个括号括起来的子串 |
leftContext |
最近一次匹配以左的子串 |
multiline |
是否进行多行匹配(bool型) |
prototype |
允许附加属性给对象 |
rightContext |
最近一次匹配以右的子串 |
source |
正则表达式模式 |
lastIndex |
最后一次匹配的索引
|
|
正则表达式对象的方法
方法 |
含义 |
compile |
正则表达式比较 |
exec |
执行查找 |
test |
进行匹配 |
toSource |
返回特定对象的定义(literal representing),其值可用来创建一个新的对象。重载Object.toSource方法得到的。
|
toString |
返回特定对象的串。重载Object.toString方法得到的。 |
valueOf |
返回特定对象的原始值。重载Object.valueOf方法得到 |
|
例子
<script language = "JavaScript">
var myReg = /(w+)s(w+)/;
var
str = "John Smith";
var newstr = str.replace(myReg, "$2, $1");
document.write(newstr);
</script>
将输出"Smith, John"
〓简介〓
字符意义:对于字符,通常表示按字面意义,指出接着的字符为特殊字符,不作解释。
例如:/b/匹配字符'b',通过在b
前面加一个反斜杠,也就是/b/,则该字符变成特殊字符,表示匹配一个单词的分界线。或者:对于几个字符,通常说明是特殊的,指出紧接着的字符不是特殊的,而应该按字面解释。例如:*是一个特殊字符,匹配任意个字符(包括0个字符);例如:/a*/意味匹配0个或多个a。为了匹配字面上的*,在a前面加一个反斜杠;例如:/a*/匹配'a*'。
〓正文〓
字符
意义:对于字符,通常表示按字面意义,指出接着的字符为特殊字符,不作解释。
例如:/b/匹配字符'b',通过在b
前面加一个反斜杠,也就是/b/,则该字符变成特殊字符,表示
匹配一个单词的分界线。
或者:
对于几个字符,通常说明是特殊的,指出紧接着的字符不是特殊的,而应该按字面解释。
例如:*是一个特殊字符,匹配任意个字符(包括0个字符);例如:/a*/意味匹配0个或多个a。
为了匹配字面上的*,在a前面加一个反斜杠;例如:/a*/匹配'a*'。
字符^
意义:表示匹配的字符必须在最前边。
例如:/^A/不匹配"an A,"中的'A',但匹配"An A."中最前面的'A'。
字符$
意义:与^类似,匹配最末的字符。
例如:/t$/不匹配"eater"中的't',但匹配"eat"中的't'。
字符*
意义:匹配*前面的字符0次或n次。
例如:/bo*/匹配"A ghost booooed"中的'boooo'或"A bird
warbled"中的'b',但不匹配"A goat g
runted"中的任何字符。
字符+
意义:匹配+号前面的字符1次或n次。等价于{1,}。
例如:/a+/匹配"candy"中的'a'和"caaaaaaandy."中的所有'a'。
字符?
意义:匹配?前面的字符0次或1次。
例如:/e?le?/匹配"angel"中的'el'和"angle."中的'le'。
字符.
意义:(小数点)匹配除换行符外的所有单个的字符。
例如:/.n/匹配"nay, an apple is on the
tree"中的'an'和'on',但不匹配'nay'。
字符(x)
意义:匹配'x'并记录匹配的值。
例如:/(foo)/匹配和记录"foo
bar."中的'foo'。匹配子串能被结果数组中的素[1], ..., [n] 返
回,或被RegExp对象的属性$1, ..., $9返回。
字符x|y
意义:匹配'x'或者'y'。
例如:/green|red/匹配"green apple"中的'green'和"red
apple."中的'red'。
字符{n}
意义:这里的n是一个正整数。匹配前面的n个字符。
例如:/a{2}/不匹配"candy,"中的'a',但匹配"caandy,"
中的所有'a'和"caaandy."中前面的两个
'a'。
字符{n,}
意义:这里的n是一个正整数。匹配至少n个前面的字符。
例如:/a{2,}不匹配"candy"中的'a',但匹配"caandy"中的所有'a'和"caaaaaaandy."中的所有'a'
字符{n,m}
意义:这里的n和m都是正整数。匹配至少n个最多m个前面的字符。
例如:/a{1,3}/不匹配"cndy"中的任何字符,但匹配 "candy,"中的'a',"caandy," 中的前面两个
'a'和"caaaaaaandy"中前面的三个'a',注意:即使"caaaaaaandy" 中有很多个'a',但只匹配前面的三
个'a'即"aaa"。
字符[xyz]
意义:一字符列表,匹配列出中的任一字符。你可以通过连字符-指出一个字符范围。
例如:[abcd]跟[a-c]一样。它们匹配"brisket"中的'b'和"ache"中的'c'。
字符[^xyz]
意义:一字符补集,也就是说,它匹配除了列出的字符外的所有东西。 你可以使用连字符-指出一
字符范围。
例如:[^abc]和[^a-c]等价,它们最早匹配"brisket"中的'r'和"chop."中的'h'。
字符[b]
意义:匹配一个空格(不要与b混淆)
字符b
意义:匹配一个单词的分界线,比如一个空格(不要与[b]混淆)
例如:/bnw/匹配"noonday"中的'no',/wyb/匹配"possibly yesterday."中的'ly'。
字符B
意义:匹配一个单词的非分界线
例如:/wBn/匹配"noonday"中的'on',/yBw/匹配"possibly
yesterday."中的'ye'。
字符cX
意义:这里的X是一个控制字符。匹配一个字符串的控制字符。
例如:/cM/匹配一个字符串中的control-M。
字符d
意义:匹配一个数字,等价于[0-9]。
例如:/d/或/[0-9]/匹配"B2 is the suite
number."中的'2'。
字符D
意义:匹配任何的非数字,等价于[^0-9]。
例如:/D/或/[^0-9]/匹配"B2 is the suite
number."中的'B'。
字符f
意义:匹配一个表单符
字符n
意义:匹配一个换行符
字符r
意义:匹配一个回车符
字符s
意义:匹配一个单个white空格符,包括空格,tab,form feed,换行符,等价于[ fnrtv]。
例如:/sw*/匹配"foo bar."中的' bar'。
字符S
意义:匹配除white空格符以外的一个单个的字符,等价于[^ fnrtv]。
例如:/S/w*匹配"foo
bar."中的'foo'。
字符t
意义:匹配一个制表符
字符v
意义:匹配一个顶头制表符
字符w
意义:匹配所有的数字和字母以及下划线,等价于[A-Za-z0-9_]。
例如:/w/匹配"apple,"中的'a',"$5.28,"中的'5'和"3D."中的'3'。
字符W
意义:匹配除数字、字母外及下划线外的其它字符,等价于[^A-Za-z0-9_]。
例如:/W/或者/[^$A-Za-z0-9_]/匹配"50%."中的'%'。
字符n
意义:这里的n是一个正整数。匹配一个正则表达式的最后一个子串的n的值(计数左圆括号)。
例如:/apple(,)sorange1/匹配"apple, orange, cherry, peach."中的'apple, orange',下面
有一个更加完整的例子。
注意:如果左圆括号中的数字比n指定的数字还小,则n取下一行的八进制escape作为描述。
字符ooctal和xhex
意义:这里的ooctal是一个八进制的escape值,而xhex是一个十六进制的escape值,允许在一个正则表达式中嵌入ASCII码。
内存模型 (memory model)
内存模型描述的是程序中各变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节.
不同平台间的处理器架构将直接影响内存模型的结构.
在C或C++中, 可以利用不同操作平台下的内存模型来编写并发程序. 但是, 这带给开发人员的是, 更高的学习成本.
相比之下, java利用了自身虚拟机的优势, 使内存模型不束缚于具体的处理器架构, 真正实现了跨平台.
(针对hotspot jvm, jrockit等不同的jvm, 内存模型也会不相同)
内存模型的特征:
a, Visibility 可视性 (多核,多线程间数据的共享)
b, Ordering 有序性 (对内存进行的操作应该是有序的)
java 内存模型
(
java memory model
)
根据Java Language Specification中的说明, jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。
每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。
其中, 工作内存里的变量, 在多核处理器下, 将大部分储存于处理器高速缓存中, 高速缓存在不经过内存时, 也是不可见的.
jmm怎么体现 可视性(Visibility) ?
在jmm中, 通过并发线程修改变量值, 必须将线程变量同步回主存后, 其他线程才能访问到.
jmm怎么体现 有序性(Ordering) ?
通过java提供的同步机制或volatile关键字, 来保证内存的访问顺序.
缓存一致性(cache coherency)
什么是缓存一致性?
它是一种管理多处理器系统的高速缓存区结构,其可以保证数据在高速缓存区到内存的传输中不会丢失或重复。(来自wikipedia)
举例理解:
假如有一个处理器有一个更新了的变量值位于其缓存中,但还没有被写入主内存,这样别的处理器就可能会看不到这个更新的值.
解决缓存一致性的方法?
a, 顺序一致性模型:
要求某处理器对所改变的变量值立即进行传播, 并确保该值被所有处理器接受后, 才能继续执行其他指令.
b, 释放一致性模型: (类似jmm cache coherency)
允许处理器将改变的变量值延迟到释放锁时才进行传播.
jmm缓存一致性模型 - "happens-before ordering(先行发生排序)"
一般情况下的示例程序:
x = 0;
y = 0;
i = 0;
j = 0;
// thread A
y = 1;
x = 1;
// thread B
i = x;
j = y;
在如上程序中, 如果线程A,B在无保障情况下运行, 那么i,j各会是什么值呢?
答案是, 不确定. (00,01,10,11都有可能出现)
这里没有使用java同步机制, 所以 jmm 有序性和可视性 都无法得到保障.
happens-before ordering(
先行发生排序)
如何避免这种情况?
排序原则已经做到:
a,
在程序顺序中,
线程中的每一个操作, 发生在当前操作后面将要出现的每一个操作之前.
b, 对象监视器的解锁发生在等待获取对象锁的线程之前.
c, 对volitile关键字修饰的变量写入操作, 发生在对该变量的读取之前.
d,
对一个线程的 Thread.start() 调用 发生在启动的线程中的所有操作之前.
e, 线程中的所有操作 发生在从这个线程的 Thread.join()成功返回的所有其他线程之前.
为了实现
happends-before ordering原则, java及jdk提供的工具:
a, synchronized关键字
b, volatile关键字
c, final变量
d, java.util.concurrent.locks包(since jdk 1.5)
e, java.util.concurrent.atmoic包(since jdk 1.5)
...
使用了happens-before ordering的例子:
(1) 获取对象监视器的锁(lock)
(2) 清空工作内存数据, 从主存复制变量到当前工作内存, 即同步数据 (read and load)
(3) 执行代码,改变共享变量值 (use and assign)
(4) 将工作内存数据刷回主存 (store and write)
(5) 释放对象监视器的锁 (unlock)
注意: 其中4,5两步是同时进行的.
这边最核心的就是第二步, 他同步了主内存,即前一个线程对变量改动的结果,可以被当前线程获知!(利用了happens-before ordering原则)
对比之前的例子
如果多个线程同时执行一段未经锁保护的代码段,很有可能某条线程已经改动了变量的值,但是其他线程却无法看到这个改动,依然在旧的变量值上进行运算,最终导致不可预料的运算结果。
经典j2ee设计模式Double-Checked Locking失效问题
双重检查锁定失效问题,一直是JMM无法避免的缺陷之一.了解DCL失效问题, 可以帮助我们深入JMM运行原理.
要展示DCL失效问题, 首先要理解一个重要概念- 延迟加载(lazy loading).
非单例的单线程延迟加载示例:
class Foo
{
private Resource res = null;
public Resource getResource()
{
// 普通的延迟加载
if (res == null)
res = new Resource();
return res;
}
}
非单例的
多线程延迟加载示例:
Class Foo
{
Private Resource res = null;
Public synchronized
Resource getResource()
{
// 获取实例操作使用同步方式, 性能不高
If (res == null) res = new Resource();
return res;
}
}
非单例的
DCL多线程延迟加载示例:
Class Foo
{
Private Resource res = null;
Public Resource getResource()
{
If (res == null)
{
//只有在第一次初始化时,才使用同步方式.
synchronized(this)
{
if(res == null)
{
res = new Resource();
}
}
}
return res;
}
}
Double-Checked Locking看起来是非常完美的。但是很遗憾,根据Java的语言规范,上面的代码是不可靠的。
出现上述问题, 最重要的2个原因如下:
1, 编译器优化了程序指令, 以加快cpu处理速度.
2, 多核cpu动态调整指令顺序, 以加快并行运算能力.
问题出现的顺序:
1, 线程A, 发现对象未实例化, 准备开始实例化
2, 由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将
共享变量的引用指向
部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.
3, 线程B, 发现部分构造的对象已不是null, 则直接返回了该对象.
不过, 一些著名的开源框架, 包括jive,lenya等也都在使用DCL模式, 且未见一些极端异常.
说明, DCL失效问题的出现率还是比较低的.
接下来就是性能与稳定之间的选择了?
DCL的替代
Initialize-On-Demand
:
public class Foo {
// 似有静态内部类, 只有当有引用时, 该类才会被装载
private static class LazyFoo {
public static Foo foo = new Foo();
}
public static Foo getInstance() {
return LazyFoo.foo;
}
}
维基百科的DCL解释:
http://en.wikipedia.org/wiki/Double-checked_locking
DCL的完美解决方案:
http://www.theserverside.com/patterns/thread.tss?thread_id=39606
总结:
多线程编程, 针对有写操作的变量, 必须 保证其所有引用点与主存中数据一致(考虑采用同步或volatile)
.