【问题标题】:Reformatting code with Regular Expressions使用正则表达式重新格式化代码
【发布时间】:2011-01-09 13:29:35
【问题描述】:

我们有一个ArrayList 几个类中的项目,每次我想在列表中插入一个新项目时都会给我带来麻烦。以我的方式设计类是我的错误,但现在更改设计会比它的价值更令人头疼(官僚瀑布模型。)我应该预料到客户提供给我们的文档的格式更改瀑布该死的。

我想在 python 中编写一个简单的脚本,该脚本进入一个类,将项目添加到列表中,然后递增以下项目的所有检索。这听起来不太解释:

Foo extends Bar{
    public Foo(){
        m_Tags.add("Jane");
        m_Tags.add("Bob");
        m_Tags.add("Jim");
    }

    public String GetJane() { return m_ParsedValue.get( m_Tags.get(1) ); }
    public String GetBob() { return m_ParsedValue.get( m_Tags.get(2) ); }
    public String GetJim() { return m_ParsedValue.get( m_Tags.get(3) ); }
}

你看我是否想在“Jane”和“Bob”之间添加一个值,然后我必须在 Get* 函数中增加整数。我只想用 Python 编写一个简单的脚本来为我工作。我非常尊重的人建议使用正则表达式。

编辑:

是的,LinkedHashMap。如此简单,如此简单,现在不在设计规范中。我讨厌瀑布。恨之入骨。这整个部分是“不应该花费太多时间来设计”的“小”和“简单”的部分。我犯了错误。它现在卡在石头上了。

【问题讨论】:

  • 让我直截了当地说:你有大量难以管理的 Java 代码,其中填充了幻数和硬编码字符串,你想在中间插入一个并使用 python 递增以下数字?
  • 你为什么不使用 HashMap 呢?只需使用字符串作为键并返回您想要的数字......在我看来这是一种更自然的方式。
  • @Jorenko:是和不是。这些字符串取自专有格式的客户文档,这些文档传递给我们的应用程序。代码不大,也没有违反 DRY。然而,你是对的。有很多神奇的数字,是的,我想在中间插入一个。
  • @Kelben - LinkedHashMap,你说得对。我只是在做设计时没有想到要使用它。我现在正在为疏忽买单。
  • @wheaties: 你不能做类似has_map.put("Jane", new Integer(i++)); 之类的事情来跟踪订单(出现的第一个名字是0,第二个1,等等......)然后让@ 987654324@ 以相同的顺序。将保留文档中的顺序,以及要返回的数字。

标签: java python regex perl


【解决方案1】:

不要使用正则表达式。创建将名称映射到数字的符号常量(例如使用枚举)。

【讨论】:

  • 从技术上讲,如果我必须从头开始重新设计,我会为每个组件创建一个命名变量,将它们分配给一个列表,然后将该列表传递给解析函数。那么我就不需要处理所有这些神奇的数字了。
  • 您不需要重新设计。现在只需添加常量。然后有脚本,如果你必须使用它,增加常量。
【解决方案2】:

我现在正在这样做(嗯,非常相似),但使用的是 Excel 和 VBA 宏。所有的商业价值都在电子表格中组织和排序。我只需单击一个按钮即可为选定的单元格生成适当的代码,然后复制粘贴到 IDE。更好的是,我每行都有几个“代码列”。其中一些生成查询、一些 XSL 转换和一些过程。对于一行业务数据,我可以很容易的得到所有三种类型的生成代码。

我发现这(重新生成)比重新格式化现有代码要容易得多。

【讨论】:

  • 这听起来像是系统的噩梦。
  • @matt b:起初我也这么认为。分析师在电子表格中维护业务数据(它们实际上组织得很好),所以我可以轻松地复制它们,然后应用我的宏来获取大量几乎不需要手动调整的样板代码。它的开发速度非常快,并且与业务需求完全匹配——这也有助于发现需求中的错误。
【解决方案3】:

您希望您的正则表达式在标记之间的空白方面与编译器一样灵活。这样做并模仿空格的使用会使模式变得非常混乱。下面的代码(抱歉:Perl,不是 Python)就地编辑您的源文件。

#! /usr/bin/perl -i.bak    
use warnings;
use strict;
my $template =
  '^( public
      String
      Get)(\w+)( \( \) { return
        m_ParsedValue . get \( m_Tags . get \( )(\d+)( \) \) ; } )$';
$template =~ s/ +/\\s*/g;
$template =~ s/(\r?\n)+/\\s+/g;
my $getter = qr/$template/x;

die "Usage: $0 after new-name source ..\n" unless @ARGV >= 3;
my $after = shift;
my $add   = shift;
my $index;
while (<>) {
  unless (/$getter/) {
    print;
    next;
  }
  my($abc,$name,$lmno,$i,$xyz) = ($1,$2,$3,$4,$5);
  if (defined $index) {
    print join "" => $abc, $name, $lmno, ++$index, $xyz;
  }
  else {
    if ($name eq $after) {
      $index = $i;
      print; print join "" => $abc, $add, $lmno, ++$index, $xyz;
    }
    else { print; }
  }
}

例如,

$ ./add-after Jane Foo code.java
$猫代码.java
Foo 扩展 Bar{
    公共Foo(){
        m_Tags.add("简");
        m_Tags.add("鲍勃");
        m_Tags.add("吉姆");
    }

    公共字符串 GetJane() { return m_ParsedValue.get( m_Tags.get(1) ); }
    公共字符串 GetFoo() { return m_ParsedValue.get( m_Tags.get(2) ); }
    公共字符串 GetBob() { return m_ParsedValue.get( m_Tags.get(3) ); }
    公共字符串 GetJim() { return m_ParsedValue.get( m_Tags.get(4) ); }
}

【讨论】:

  • 非常感谢。我可以向了解 perl 和 python 的人展示这个。他们将能够引导我回来。
【解决方案4】:

关于不良做法的评论 - 这是您以您要求的语言提出的代码。 如果您以这种方式保留系统,最好的办法可能是让这些 java 文件在构建过程本身中自动生成——您只需在目录中的 .txt 文件中保留一个名称列表。这个脚本适合这样做。

(它不会修改您的文件,它会根据您在此处发布的模板生成新文件)

import re, sys

template = """Foo extends Bar{
    public Foo(){
%s
    }

%s
}
"""

tag_templ =   """        m_Tags.add("%s");"""
getter_templ = """    public String GetJane() { return m_ParsedValue.get( m_Tags.get(%d) ); }"""

def parse_names(filename):
    data = open(filename).read()
    names = re.findall(r'm_Tags\.add\("(.*?)"', data)
    return names

def create_file(filename, names):
    tag_lines = [tag_templ % name for name in names]
    getter_lines = [getter_templ % (i + 1) for i in range(len(names))]
    code = template % ("\n".join(tag_lines), "\n".join(getter_lines))
    file = open(filename,"wt")
    file.write(code)
    file.close()

def insert_name(after, new_name, names):
    names.insert(names.index(after) + 1, new_name)

if __name__ == "__main__":
    if len(sys.argv ) < 4:
        sys.stderr.write("Usage: changer.py <filename> <name-before-insertion> <new-name>")
        sys.exit(1)
    filename, name_before, new_name = sys.argv[1:]
    names = parse_names(filename)
    insert_name(name_before, new_name, names)
    create_file(filename, names)

【讨论】:

  • 谢谢你,谢谢你没有评论我的错误。这真是个好主意。我一直在努力朝着更务实的方向前进(一个月前刚刚完成了务实的程序员。)
  • 模板绝对是正确的方法。但是为什么不更进一步,使用真正的模板库,例如 Python 的 Template Toolkit 呢? tt2.org/python/index.html
  • 因为在这样一个简单的例子中不需要这样做? Python moto 之一是“简单胜于复杂”——即使对于真正的代码,标准库本身也有足够好的模板格式化方法来证明这种简单情况下的外部依赖是合理的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多