65.9K
CodeProject 正在变化。 阅读更多。
Home

将 Allman 风格的括号改为 Stroustrup 风格

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (2投票s)

2013 年 10 月 22 日

CPOL

2分钟阅读

viewsIcon

19503

downloadIcon

87

用于更改自动生成的代码的括号风格的程序。

引言

change_to_stroustrup_style.py 程序是一个非常简单的程序,用于更改完全使用 Allman 括号风格编写的代码的括号风格。代码非常简单,*不是*一个通用的美化程序。所做的只是将与空格位于同一行的开括号移动到前一行末尾,并在空格后添加一个空格字符。

该程序对于其预期目的非常有用。我在 codeproject 上发布了三个 C 或 C++ 代码生成器,它们都使用 Allman 括号风格编写代码。这是我首选的风格,但我意识到并非每个人都喜欢它。

Allman 风格的一个例子是

    if (a == b)
    {
        c = a;
    }
    else
    {
        d = a;
    }

即使 Allman 风格不是我首选的风格,我仍然会编写代码生成器以输出该风格,因为该风格的括号始终位于单独的一行上,因此对于将代码转换为其他风格的程序来说,无需进行复杂的解析。

change_to_stroustrup_style.py 程序将 Allman 风格代码文件的风格更改为 Stroustrup 风格的括号。如果将上面的代码更改为 Stroustrup 风格,它将变为

    if (a == b) {
        c = a;
    }
    else {
        d = a;
    }

该程序仅对格式正确的 Allman 风格程序有效。

该程序还提供了一个使用 Python 生成器的简单示例。

使用代码

命令格式如下

python change_to_stroustrup_style.py <file_name> [-b] 

-b 选项或 --backup 选项可用于用户希望保存原始文件备份的情况。

代码

在 Python 中,使用简单的 'for' 循环迭代文件中的所有行很常见,如下所示

    for line in input_file:
        # Code to process the string 'line' goes here.
        <code omitted>

对于这种情况,需要在代码的下一行添加开括号到前一行末尾,使用 Python 生成器获取文件的每一行比使用简单的循环需要更复杂的代码。

因此,此代码利用了 Python 生成器功能。以下函数从任何可迭代项生成一个生成器。该函数返回一个生成器实例。'yield' 语句在调用返回实例的 'next' 方法时返回下一个 item。当返回最终项目时,再次调用 'next' 方法会引发 StopIteration 类型的异常。

def get_iterable_item_generator(iterable_instance):
    """ Create a generator that provides one iterable
        item at a time.
    """
    for item in iterable_instance:
        yield item

程序

#!/usr/bin/env python
#=======================================================================
# Copyright (C) 2013 William Hallahan
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#=======================================================================
"""
    python change_to_stroustrup_style.py <file_name> [-b]

    Change bracketing style of an Allman-style C program
    to Stroustrup-style bracketing.  For example:

    if (a == b)
    {
        c = a;
    }
    else
    {
        d = a;
    }

    becomes:

    if (a == b) {
        c = a;
    }
    else {
        d = a;
    }
"""
import sys
import os
from shutil import copyfile
from argparse import ArgumentParser

def get_iterable_item_generator(iterable_instance):
    """ Create a generator that provides one iterable
        item at a time.
    """
    for item in iterable_instance:
        yield item

def execute_change_to_stroustrup_style(input_file_name, backup):
    """ Convert Allman-style to Stroustrup-style. """
    # Make a copy of the file.
    backup_file_name = 'backup_{0}'.format(input_file_name)
    copyfile(input_file_name, backup_file_name)
    # Read the copied file and write to a new file with the original
    # file name.
    with open(input_file_name, 'w') as outfile:
        with open(backup_file_name) as infile:
            line_generator = get_iterable_item_generator(infile)
            line = ''
            try:
                line = line_generator.next().strip('\n')
                while True:
                    next_line = line_generator.next()
                    while next_line.strip() == '{':
                        line = '{0} {1}'.format(line, '{')
                        next_line = line_generator.next()
                    outfile.write('{0}\n'.format(line))
                    line = next_line.strip('\n')
            except StopIteration:
                pass
            outfile.write('{0}\n'.format(line))
    # Optionally delete the copy of the original file.
    if not backup:
        os.remove(backup_file_name)
    return 0

# Start of main program.
def main(argv=None):
    # Initialize the command line parser.
    parser = ArgumentParser(description='The program converts C or C++ code formatted in Allman-style to Strousop-style.',
                            epilog='Copyright (c) 2013 William Hallahan - All Rights Reserved.',
                            add_help=True,
                            argument_default=None, # Global argument default
                            usage=__doc__)
    parser.add_argument(action='store', dest='input_file_name', help='Print the help information.')
    parser.add_argument('-b', '--backup', action='store_true', dest='backup', default=False,
                        help='Save a backup of the original file.')
    # Parse the command line.
    arguments = parser.parse_args(args=argv)
    input_file_name = arguments.input_file_name
    backup = arguments.backup
    status = 0
    try:
        execute_change_to_stroustrup_style(input_file_name, backup)
    except ValueError as value_error:
        print value_error
        status = -1
    except EnvironmentError as environment_error:
        print environment_error
        status = -1
    return status

if __name__ == "__main__":
    sys.exit(main())

关注点

该程序可以轻松修改为编写 K&R 风格。K&R 风格与 Stroustrup 风格不同地格式化 'if' 语句的 'else' 子句。对于前面的示例,K&R 风格是

    if (a == b) {
        c = a;
    } else {
        d = a;
    }  

顺便说一下,我总是添加开括号和闭括号,即使它们不需要,如上面的示例所示。这使得代码更易于维护。企业发现,代码的成本通常有 85% 用于维护,因此易于维护通常比其他考虑因素更重要。

历史 

  • 初始发布。
© . All rights reserved.