【问题标题】:Script to Parse and Change Numbers解析和更改数字的脚本
【发布时间】:2009-06-22 23:11:05
【问题描述】:

在编辑特定类型的文件时,我经常使用数字,而且这大多是乏味的工作。该文件的格式如下:

damagebase = 8.834
    "abc_foo.odf" 3.77
    "def_bar.odf" 3.77
    "ghi_baz.odf" 3.77
    "jkl_blah.odf" 4.05
    ...

对于编写一个解析这个并让我以编程方式更改每个数字的脚本,你有什么建议?

语言:我使用 C#、一些 F#(菜鸟)和 Lua。如果您建议正则表达式,您能否提供具体的,因为我不熟悉它们?

【问题讨论】:

  • 请详细说明。那里有两种不同的行格式。 'damagebase' 格式是否在文件中再次出现,或者它是某种标题?您想以编程方式更改 all 数字还是仅更改非标题数字?更改号码的方法有多复杂?它涉及简单的加法还是更复杂,例如应用运行平均值?
  • damagebase 行是一个标题,我希望能够对每行(包括标题)上的数字应用倍数。
  • 感谢您对 c# 的回答感到更自在,但一般来说,您确实应该学习足够的 perl 或 awk,这样您就不必求助于 c# 来解决这类问题。
  • 这是我遇到问题的正则表达式。 “我在这里使用了正确的数字批处理字符吗?我该如何匹配?哎呀!它吃了我的字符串......”:D

标签: c# scripting numbers fileparsing


【解决方案1】:

Perl 非常适合这样的东西。这是一个 perl 脚本,可以做你想做的事。

#!/usr/bin/env perl

$multiplier = 2.0;

while (<>)
{
    $n = /=/ ? 2 : 1;
    @tokens = split;
    $tokens[$n] *= $multiplier;

    print "\t" if not /=/;
    print join(' ', @tokens) . "\n";
}

用法:

./file.pl input_file > output_file

【讨论】:

  • Perl 在这些方面确实更好。
  • 为了展示如何轻松编写脚本,我在另一个答案中添加了一个 AWK 表单。
【解决方案2】:

如果这真的是你想做的全部,请使用 awk:

awk '{$NF *= 2.5 ; print }' < input_file > output_file

已编辑:好的,如果您想保留所描述的空白,这应该可以工作(尽管它变得不优雅)。

awk '{$NF *= 2.5} /^\"/{print "\t" $0} !/^\"/{print}' < input_file > output_file

【讨论】:

  • 这会吃掉非标题行的前导标签。
  • 嗯,我还没有真正听说过 awk。这是什么?
  • 好吧,你有疯狂的 awk 技能。如果可以的话,我会投票+100。
【解决方案3】:

您可以像这样使用 AWK(请注意如何轻松转换格式),

sed 's/damagebase =/damagebase=/g' input.txt |\
    awk '{printf "     %s %s\n",$1,3.1*$2}' |\
    sed 's/.*damagebase=/damagebase =/g'

在此示例脚本中,我将第二列乘以 3.1
请注意,要恢复您的格式,
在 printf 的开头插入了一个制表符,
这两个sed 命令将您的格式来回转换为适合 AWK 命令的格式

【讨论】:

  • 啊,已经有另一个 AWK 答案了。没有注意到它。然而,您可以看到为您的目的编写脚本的各种方式。
【解决方案4】:

您可以匹配非空白的运行并下注到Double.Parse

int multiplier = 3;

string input =
  "damagebase = 8.834\n" +
  "  \"abc.odf\" 3.77\n" +
  "  \"def.odf\" 3.77\n" +
  "  \"ghi.odf\" .77\n" +
  "  \"jkl.odf\" -4.05\n" +
  "  \"mno.odf\" 5\n";

Regex r = new Regex(@"^(\w+)\s*=\s*(\S+)" +
                    @"(?:\s+""([^""]+)""\s+(\S+))+",
                    RegexOptions.Compiled | RegexOptions.Multiline);

Match m = r.Match(input);
if (m.Success) {
  double header = Double.Parse(m.Groups[2].Value);
  Console.WriteLine("{0} = {1}", m.Groups[1].Value,
                                 header * multiplier);

  CaptureCollection files = m.Groups[3].Captures;
  CaptureCollection nums  = m.Groups[4].Captures;
  for (int i = 0; i < files.Count; i++) {
    double val = Double.Parse(nums[i].Value);
    Console.WriteLine(@"  ""{0}"" {1}", files[i].Value,
                                        val * multiplier);
  }
}
else
  Console.WriteLine("no match");

运行它会给出

damagebase = 26.502
  "abc.odf" 11.31
  "def.odf" 11.31
  "ghi.odf" 2.31
  "jkl.odf" -12.15
  "mno.odf" 15

【讨论】:

    【解决方案5】:

    我试过了

    static void Main(string[] args)
    {
        Console.WriteLine("Please enter the multiplier:");
        string stringMult = Console.ReadLine();
        int multiplier;
        Int32.TryParse(stringMult, out multiplier);
        StreamReader sr = new StreamReader(@"C:\Users\[obscured]\Desktop\Fleetops Mod\Data To Process.txt", true);
        string input = sr.ReadToEnd();
        sr.Close();
        StreamWriter sw = new StreamWriter(@"C:\Users\[obscured]\Desktop\Fleetops Mod\Data To Process.txt", false);
        Regex r = new Regex(@"^(\w+)\s*=\s*(\S+)" +
                @"(?:\s+""([^""]+)""\s+(\S+))+",
                RegexOptions.Compiled | RegexOptions.MultiLine);
        Match m = r.Match(input);
        if (m.Success) {
            double header = Double.Parse(m.Groups[2].Value);
            sw.WriteLine("{0} = {1}", m.Groups[1].Value,
                             header * multiplier);
            CaptureCollection files = m.Groups[3].Captures;
            CaptureCollection nums  = m.Groups[4].Captures;
            for (int i = 0; i < files.Count; i++) {
                double val = Double.Parse(nums[i].Value);
                sw.WriteLine(@"  ""{0}"" {1}", files[i].Value,
                                    val * multiplier);
            }
        }
        else
            Console.WriteLine("no match");
        sw.Close();
        Console.WriteLine("Done!");
        Console.ReadKey();
    }
    

    (感谢 gbacon) 即使我输入正确的数据,它也会返回“不匹配”。为什么这样做? 这是测试数据:

    damagebase = 8.098
        "bor_adaptor_03.odf" 3.77
        "bor_adaptor_13.odf" 3.77
        "bor_adaptor_23.odf" 3.77
        "bor_adaptor_33.odf" 4.05
        "bor_adaptor_R3.odf" 3.77
        "bor_adaptor_T3.odf" 3.77
        "bor_cube_BHHHMM.odf" 6.48
        "bor_cube_BRHHHM.odf" 4.52
        "bor_cube_BRHHMM.odf" 6.48
        "bor_cube_BTHHHM.odf" 4.52
        "bor_cube_BTHHMM.odf" 6.48
        "bor_cube_BTRHHM.odf" 4.52
        "bor_cube_BTRHMM.odf" 6.48
        "bor_cube_BTTHHM.odf" 4.52
        "bor_cube_BTTHMM.odf" 6.48
        "bor_cube_BTTRHM.odf" 4.52
        "bor_cube_BTTRMM.odf" 6.48
        "bor_cube_BTTTHM.odf" 4.52
        "bor_cube_BTTTMM.odf" 6.48
        "bor_cube_BTTTRM.odf" 4.52
        "bor_cube_RHHHMM.odf" 6.48
        "bor_cube_THHHMM.odf" 6.48
        "bor_cube_TRHHHM.odf" 4.52
        "bor_cube_TRHHMM.odf" 6.48
        "bor_cube_TTHHHM.odf" 4.52
        "bor_cube_TTHHMM.odf" 6.48
        "bor_cube_TTRHHM.odf" 4.52
        "bor_cube_TTRHMM.odf" 6.48
        "bor_cube_TTTHHM.odf" 4.52
        "bor_cube_TTTHMM.odf" 6.48
        "bor_cube_TTTRHM.odf" 4.52
        "bor_cube_TTTRMM.odf" 6.48
        "dom_battle_cruiserY2r6.odf" 4.123
        "dom_battle_cruiserYr6.odf" 4.123
        "dom_battle_cruiserZ2r6.odf" 4.123
        "dom_battle_cruiserZr6.odf" 4.123
        "dom_battle_cruiser_fed2r6.odf" 4.123
        "dom_battle_cruiser_fedr6.odf" 4.123
        "dom_defenderr4.odf" 7.775
        "dom_defenderr5.odf" 7.452
        "dom_defenderr6.odf" 3.793
        "dom_dreadnought_borr4.odf" 3.77
        "dom_dreadnought_borr5.odf" 3.77
        "dom_dreadnought_borr6.odf" 3.77
        "dom_dreadnought_fedr4.odf" 3.77
        "dom_dreadnought_fedr5.odf" 3.77
        "dom_dreadnought_fedr6.odf" 3.77
        "dom_dreadnought_klir4.odf" 3.77
        "dom_dreadnought_klir5.odf" 3.77
        "dom_dreadnought_klir6.odf" 3.77
        "dom_dreadnought_romr4.odf" 3.77
        "dom_dreadnought_romr5.odf" 3.77
        "dom_dreadnought_romr6.odf" 3.77
        "dom_intercept_destr4.odf" 5.346
        "dom_intercept_destr5.odf" 2.673
        "dom_intercept_destr6.odf" 2.673
        "dom_intercept_dest_romr4.odf" 5.346
        "dom_intercept_dest_romr5.odf" 2.673
        "dom_intercept_dest_romr6.odf" 2.673
        "fed_ambassadorMr6.odf" 5.67
        "fed_ambassadorr6.odf" 5.67
        "fed_intrepidYr6.odf" 5.67
        "fed_intrepidZr6.odf" 5.67
        "fed_intrepid_borr6.odf" 5.67
        "fed_mirandaii.odf" 5.905
        "fed_mirandaiiM.odf" 5.905
        "fed_mirandaiiMr2.odf" 5.905
        "fed_mirandaiiMr3.odf" 5.905
        "fed_mirandaiiMr4.odf" 5.905
        "fed_mirandaiiMr5.odf" 5.905
        "fed_mirandaiiMr6.odf" 5.905
        "fed_mirandaiir2.odf" 5.905
        "fed_mirandaiir3.odf" 5.905
        "fed_mirandaiir4.odf" 5.905
        "fed_mirandaiir5.odf" 5.905
        "fed_mirandaiir6.odf" 5.905
        "fed_monsoonr4.odf" 4.782
        "fed_monsoonr5.odf" 2.31
        "fed_monsoonr6.odf" 3.726
        "fed_monsoonZr4.odf" 4.782
        "fed_monsoonZr5.odf" 2.31
        "fed_monsoonZr6.odf" 3.726
        "fed_monsoon_bor.odf" 4.52
        "fed_monsoon_borr2.odf" 4.52
        "fed_monsoon_borr3.odf" 4.52
        "fed_monsoon_borr4.odf" 6.32
        "fed_monsoon_borr5.odf" 3.315
        "fed_monsoon_borr6.odf" 2.916
        "fed_monsoon_klir4.odf" 4.782
        "fed_monsoon_klir5.odf" 2.31
        "fed_monsoon_klir6.odf" 3.726
        "fed_sovereignr4.odf" 6.69
        "fed_sovereignr5.odf" 5.51
        "fed_sovereignr6.odf" 5.51
        "fed_sovereignYr4.odf" 6.69
        "fed_sovereignYr5.odf" 5.51
        "fed_sovereignYr6.odf" 5.51
        "kli_brelr4.odf" 7.452
        "kli_brelr5.odf" 6.69
        "kli_brelr6.odf" 6.69
        "kli_brelZr4.odf" 7.452
        "kli_brelZr5.odf" 6.69
        "kli_brelZr6.odf" 6.69
        "kli_brel_borr4.odf" 7.452
        "kli_brel_borr5.odf" 6.69
        "kli_brel_borr6.odf" 6.69
        "kli_brel_romr4.odf" 7.452
        "kli_brel_romr5.odf" 6.69
        "kli_brel_romr6.odf" 6.69
        "kli_edjenr4.odf" 7.452
        "kli_edjenr5.odf" 6.69
        "kli_edjenr6.odf" 6.69
        "kli_kvortr6.odf" 6.69
        "kli_kvortZr6.odf" 6.69
        "kli_kvort_fedr6.odf" 6.69
        "rom_generix_dreadr4.odf" 7.723
        "rom_generix_dreadr5.odf" 7.21
        "rom_generix_dreadr6.odf" 7.21
        "rom_generix_dreadYr4.odf" 7.723
        "rom_generix_dreadYr5.odf" 7.21
        "rom_generix_dreadYr6.odf" 7.21
        "rom_generix_dread_klir4.odf" 7.723
        "rom_generix_dread_klir5.odf" 7.21
        "rom_generix_dread_klir6.odf" 7.21
    

    我的理论是,因为每个非标题行之前的空格是一个制表符(在这里不会以这种方式显示),所以正则表达式不匹配。如果您想知道,空格很重要。

    【讨论】:

    • 将 RegexOptions.Multiline 添加到对 Regex 构造函数的调用中。我的回答中也有同样的修订。
    • 第一次尝试对我来说运行良好,但我能够通过在标题行之前添加一个空行来重现您看到的行为。在正则表达式中,^ 表示“字符串的开头”,但使用 Multiline 选项,它可以匹配任何行的开头。另请注意,\s 匹配空格,其中包括空格和制表符。
    • 现在它运行但输出中的每个数字都设置为零。我会尝试一下,看看我能不能让它工作……有什么不同的原因会导致这种情况吗?
    • 我知道原因了。不知何故,乘数被设置为 zro。为什么是这样?我没有看到我给它的输入数字有什么问题......
    • 我明白了。这是修复输入类型的问题。感谢您的帮助!
    猜你喜欢
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    • 2015-08-10
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 2012-05-20
    相关资源
    最近更新 更多