可移动式智能报价恶魔

DiveIntoMark,Mark Pilgrim有一些关于黑客可移动类型的优秀技巧生成智能报价(a.k.a引号,也印刷商的报价)这让齿轮将在万博manbetx贴吧——当然,这可能,应该更容易。

[2002年11月13日:如果您使用的是Movable Type 2.5或更高版本,这些说明现在已被我的新版本废弃SmartyPants插件]

[2002年10月5日:This article was edited on October 5 to (1) fix a few bugs; (2) take advantage of improvements in the latest versions of Brad Choate’s plug-ins; and (3) improve the smart-quotes algorithm看到本文有关更改的详细信息。]

对于,至少在过去15年左右,Mac用户已经开始期望通过输入常规撇号和引号自动发生正确的引号在他们的文字处理器中,就是这样然而,在HTML标记中,智能引用一直是屁股中的王室痛苦。

在HTML中获取智能引号的问题在于,引号字符不是标准跨平台ASCII字符集的一部分,这意味着如果您希望它们在所有平台上正确显示,则需要使用实体但原始实体是丑陋和分散,很难写和编辑当你的文本是这样的:

“Who’re you?”, she said.

因此,大多数人忽略了这个问题,只是在他们的HTML中使用好的老式哑巴引号那些坚持不懈并坚持做正确事情的排版书呆子,比如Textism的迪恩艾伦,通常诉诸预检脚本生成智能报价实体换句话说,分为三个步骤:

  1. 使用纯文本撰写,编辑和大惊小怪的博客文章。
  2. 起飞前的运行脚本(s)来生成所需的实体。
  3. 将文章发布到网上。

但现代博客工具的目的是,他们发布的文章容易正常,non-obsessive人只会容忍步骤1和3:写,然后发布他们是对的 - 教育报价不是一个难以解决的问题,你的软件应该能够为你做到。

Our own preflight scripts here at 万博manbetx贴吧 are BBEdit text filters, written in PerlBut why invoke them manually, when Movable Type itself is extensible with Perl? Why indeed.

它应该工作的方式是编写使用普通易打哑报价、活字的数据库中存储的文章与愚蠢的引用,并引用教育发生在模板层,当文章被出版。

这是我们的解决方案:

  1. 安装两个Brad Choate的免费Movable Type插件:MTPerlScript(版本1.3或更高版本)MTMacro(版本1.5或更高版本)它们很容易安装 - 说明包含在自述文件中一定要安装最新版本的插件——旧版本不会使用下面的宏定义先生朝圣者正在使用先生之一Choate的其他插件,MTRegex,但我们使用的智能引号算法不能表示为单个正则表达式我们需要多个模式和一些而()循环令人惊叹的MTPerlScript插件允许我们这样做。

  2. 添加包含以下文本的模板模块我将我的模块命名为“Educate Quotes”该模块包含两件事:(1)定义新的宏<educate_quotes>tag for MT templates; and (2) the Perl script that does all our quote education, including both single and double quotesPerl脚本还创建了em破折号——像括弧的这个条款——通过将每个发生”——“(空间的破折号)变成一个真正的长破折号HTML实体。

    <MTMacroDefine ctag="educate_quotes" script="PerlScript">
    print educate_quotes::educate($MTMacroContent);
    </MTMacroDefine>
    
    
    <MTPerlScript package="educate_quotes" cache="1" once="1">
    
    sub educate {
        $_ = shift;
    
        # First, check to see if the text we're educating contains
        # markupIf it does, we need to take extra steps to avoid
        # smartening any quotes within HTML tags.
    
        if (m/<.+>/s) {
    
            # Find single quotes that need to be turned into closing
            # curly quotesThe pattern looks for text between tags.
            1 while s{
                (?<=>)          # Positive lookbehind for a ">"
                ([^<]+)?        # One or more of anything but "<", optionally.
                (?<!\s)         # Negative lookbehind for a whitespace char
                '               # A quote
                (?(1)|(?=\s))   # If $1 captured, then do nothing;
                                # if not, then make sure the next char is whitespace  
            }{$1&#8217;}xgs;
            
            # Any remaining single quotes should be turned into
            # opening curly quotes.
            1 while s/(>[^<]*)'/$1&#8216;/xgs;
            
            # Closing double-quotes (same pattern as above)
            1 while s{
                (?<=>)          # Positive lookbehind for a ">"
                ([^<]+)?        # One or more of anything but "<", optionally.
                (?<!\s)         # Negative lookbehind for a whitespace char
                "               # A quote
                (?(1)|(?=\s))   # If $1 captured, then do nothing;
                                # if not, then make sure the next char is whitespace  
            }{$1&#8221;}xgs;
            
            # Opening double-quotes
            1 while s/(>[^<]*)"/$1&#8220;/xgs;
            
            # Let's make real em-dashes while we're here.
            1 while s/(>[^<]*)(\ --\ )/$1\ &#8212;\ /gs;
        }
        else {
            # The text we're educating doesn't contain markup,
            # so we don't need anything fancy.
            
            s/(\S)'/$1&#8217;/g;    # closing single quotes
            s/'/&#8216;/g;          # opening single quotes
            
            s/(\S)"/$1&#8221;/g;    # closing double quotes
            s/"/&#8220;/g;          # opening double quotes
            
            s/ -&#45 /&#8212;/g;       # em dashes
        }
    
        return $_;
    }
    
    </MTPerlScript>
  3. 在您想要智能引号的每个博客模板中,通过插入以下代码来包含Educate Quotes模块(将它放在模板中的位置并不重要;靠近顶部的地方和任何地方一样好。)

    <$ MTInclude module =“Educate Quotes”$>
  4. Finally, wrap the MT tags whose quotes you want to educate in公吨调用我们脚本的标签例如,唯一的标签我们想教育在万博manbetx贴吧是每个条目的标题和主体这是我们以前的模板代码:

    <H1> <$ MTEntryTitle $> </ H1>
    <$ MTEntryBody $>

    以下是我们现在用来生成相同输出的内容,但是有了受过良好教育的引用:

    <MTMacroApply>
    <h1><educate_quotes><MTEntryTitle></educate_quotes></h1>
    	
    <educate_quotes><MTEntryBody></educate_quotes>
    </MTMacroApply>

备注和警告

我们吃我们自己的狗粮在万博manbetx贴吧,所以我们使用这个脚本自己(至少在撰写本文时)没有任何不良影响But bugs happen; if you find one, please do let us know.

整个事情散发出一种黑客的味道如果它是自己的插件,而不是在MTPerlScript插件内运行的脚本,它将更灵活,更安全,更容易在模板中使用。

Nerdy智能报价算法和正则表达式模式概述

好奇的读者可能会质疑为什么教育()例程就像它一样复杂乍一想,你可能会简单地使用中使用的技术其他的块——四个简单的调用替换操作符问题是当你在HTML标记中教育引号时,你不能搞乱标签内的引​​号你不想改变

< a href = " foo " >

< a href = & # 8220;foo # 8221;>

So, the first step in the script is to see if the text we’re working with contains HTML markup:

如果(m / < + > / s){

如果没有,那么巧妙地提高报价是件小事跳到其他的块和运行一些简单的替换。

如果是文字包含标记,然后我们需要使用循环来搜索每个直引号(和撇号)在标签内:

1 while s{
            (?<=>)          # Positive lookbehind for a ">"
            ([^<]+)?        # One or more of anything but "<", optionally.
            (?<!\s)         # Negative lookbehind for a whitespace char
            '               # A quote
            (?(1)|(?=\s))   # If $1 captured, then do nothing;
                            # if not, then make sure the next char is whitespace  
        }{$1&#8217;}xgs;

我们需要一个循环,因为单个正则表达式替换模式在标记之间的单个文本段中找不到多个引号在英语中,关闭单引号的模式是查找“>”,后跟一个或多个不是“<”的字符,后跟非空格字符,后跟撇号。

但如果有两个或两个以上的收单引号字符的文本,该模式只会匹配第一个,因为随后的报价不会有“>”匹配,因为正则表达式引擎搬过去第一个匹配的文本因此,我们循环该只要模式匹配,循环就会继续运行一旦我们弄清了所有引号,它就会停止并转移到下一个引号。

确定引用是打开还是关闭的逻辑非常简单:如果紧接在前面的字符是非空格,则它是结束引用如果引号是标记之后的第一个字符,并且引用之后的下一个字符是空格,则它也是结束引号(例如:如果你在引号内有“<i> italics </ i>”)一旦你改变了这些,任何余数开引号。

最后一个注意如果你真的想要使用文字直引号字符 - 就像我们在代码部分中所做的那样 - 你需要通过使用HTML实体明确地要求它们“&quot;” will give you a straight double quote character, and “&#39;” will give you a straight apostrophe.

积分

特别感谢布拉德·乔特,他不仅编写了本文所依赖的令人惊奇的插件,还写了一篇修复我原始实现中的一个明显错误的插件布莱德是男人。