【问题标题】:How to extract comment out of header file using python, perl, or sed?如何使用 python、perl 或 sed 从头文件中提取注释?
【发布时间】:2011-02-22 19:17:20
【问题描述】:

我有一个这样的头文件:

/*
 * APP 180-2 ALG-254/258/772 implementation
 * Last update: 03/01/2006
 * Issue date:  08/22/2004
 *
 * Copyright (C) 2006 Somebody's Name here
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef HEADER_H
#define HEADER_H

/* More comments and C++ code here. */

#endif /* End of file. */

我希望只提取first C 风格注释的内容,并在每行的开头删除“*”以获得具有以下内容的文件:

 APP 180-2 ALG-254/258/772 implementation
 Last update: 03/01/2006
 Issue date:  08/22/2004

 Copyright (C) 2006 Somebody's Name here
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
 3. Neither the name of the project nor the names of its contributors
    may be used to endorse or promote products derived from this software
    without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

请建议一种简单的方法来使用 Python、Perl、sed 或 Unix 上的其他方式来完成此操作。最好是单线。

【问题讨论】:

    标签: c++ python perl sed extraction


    【解决方案1】:
    sed -i -r "s/[\/\ ]{1}\*[\/\ ]?//g" YOURFILENAME
    

    这会替换文件中的 trims cmets,保留内容。这将修改 YOURFILENAME 文件。如果您不希望从行中删除 -i

    【讨论】:

    • 这很接近,但它并没有剥离第一条评论之后的所有 C++ 代码。
    • 另外,不希望对原始文件产生副作用,而是创建一个新文件。
    • printf("\\这不是评论。");和 printf("/*这也不是*/".);
    【解决方案2】:

    这应该适合你:

    sed -n '/\*\//q; /^\/\*/d; s/^ \* \?//p' <file.h >comment.txt
    

    这里有一个解释:sed(你可能知道)是一个命令,它通过一个文件将规则列表应用于每一行。每条规则都是由一个“选择器”和命令组成,只有选择选择器匹配时应用于该行。

    第一条规则有选择器/\*\//。这是一个正则表达式选择器;它匹配包含字符*/ 的任何行。这两个都需要反斜杠转义,因为它们在正则表达式中具有特殊含义。 (我假设这只会与您的情况下评论的最后一行匹配,并且应该删除整行。)命令是q,意思是“退出”。 sed 刚刚停止。通常它会打印出该行,但我提供了-n 选项,意思是“除非明确指示,否则不要打印。”

    第二条规则有选择器/^\/\*/,它又是一个正则表达式选择器,匹配行首的字符/*。同样,我假设这一行将不包含评论的一部分。 d 命令告诉 sed 删除这一行并继续前进。

    最终规则没有选择器,因此它适用于所有行(除非先前的命令阻止处理到达最终规则)。最后一条规则中的命令是替换命令s/PATTERN/REPLACEMENT/,它在行中查找与某个模式匹配的文本并将其替换为替换文本。这里的模式是^ \* \?,它匹配一个空格、一个星号和0 或1 个空格,但只在行首。替换什么都不是。所以 sed 只是简单地删除了前导空格-星号-(空格)?顺序。 p 实际上是替换命令的一个标志,它告诉 sed 打印出替换的结果。因为-n 选项,所以需要它。

    【讨论】:

    • 这很接近,它留下了空行“/*”、“”、“*/”。 / 和 */ 行应删除,“*”行保留为空白。
    • 顺便说一句,如果你能解释一下命令行是如何解释的,那会很有帮助,这样我就可以自己表演这个魔法了。
    • 是的,我知道,这些是我正在做的调整。完整的解决方案和解释即将发布。
    • 好吧,我们总是可以通过一个额外的 sed 来管道它,但那是作弊 ;-)
    • 是的 ;-) 不过这不是太难。请注意,我在最近的编辑中稍微简化了命令。
    【解决方案3】:

    Pyparsing 包含一个用于匹配来自各种语言的注释格式的内置模式。使用cStyleCommentscanString 查找源文件中的第一个注释使其余的只是字符串函数:

    c_src = open(c_source_file).read()
    
    from pyparsing import cStyleComment
    cmt = cStyleComment.scanString(c_src).next()[0][0]
    lines = [l[3:] for l in cmt.splitlines()]
    print '\n'.join(lines)
    

    scanString 是一个生成器,它在转到下一个实例之前返回每个匹配项,因此只处理第一个评论。使用您的示例代码,这将返回:

    APP 180-2 ALG-254/258/772 implementation 
    Last update: 03/01/2006 
    Issue date:  08/22/2004 
    
    Copyright (C) 2006 Somebody's Name here 
    All rights reserved. 
    
    Redistribution and use in source and binary forms, with or without 
    modification, are permitted provided that the following conditions 
    are met: 
    1. Redistributions of source code must retain the above copyright 
       notice, this list of conditions and the following disclaimer. 
    2. Redistributions in binary form must reproduce the above copyright 
       notice, this list of conditions and the following disclaimer in the 
       documentation and/or other materials provided with the distribution. 
    3. Neither the name of the project nor the names of its contributors 
       may be used to endorse or promote products derived from this software 
       without specific prior written permission. 
    
    THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
    ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
    SUCH DAMAGE. 
    

    【讨论】:

    • 即使这个软件没有通过基本测试:printf("//This is not a comment!"); 被 cppCommentStyle 当作评论,但有趣的是,cCommentStyle 没有。
    • 这里的失败只是因为你在测试中添加了一些隐含的知识,而不是在表达式中。如果您希望字符串扫描器忽略带引号的字符串,那么只需这样做:cppStyleComment.ignore(quotedString).scanString('printf("//This is not a comment");').next() 将正确引发 StopIteration,因为这种形式提供了额外的规范,即带引号的字符串中的 cmets 不重要。 (当然这里cStyleComment不匹配,cStyleComments只匹配/*...*/cmets。)
    • scanString 逐个字符地查找表达式的匹配项,在您的情况下为 cppStyleComment (同时匹配 /*...*///... cmets)。 scanString 从位置 0 开始,然后是 1,然后是 2,等等。每个都试图进行匹配。当它最终越过第一个 '"' 字符,到达第一个 '/' 字符时,它确实找到了一个有效的注释。在任何注释表达式的定义中都没有任何特殊处理引用字符串的内容。 OP 的测试用例不包括引号内的 cmets,所以我没有用这个添加的过滤器弄乱解决方案。
    猜你喜欢
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    相关资源
    最近更新 更多