tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
0
ZUGRIFFE
1325
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
  1. #1
    Registriert seit
    Dec 2001
    Ort
    Bayern
    Beiträge
    5.800
    Blog-Einträge
    5
    Hallihallo,

    hier mal meine Lösung der Aufgaben 1 und 3 in Ruby. Der Code ist nicht allzu schön, aber zum Aufräumen hab ich leider keine Zeit mehr.

    Code ruby:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    
    #!/usr/bin/env ruby
    # encoding: utf-8
     
    module GermanCardinals
      ###
      # Integer to cardinal
      ###
     
      ORD_PREFIXES = [nil] + %w( M B Tr Quadr Quint Sext Sept Okt Non Dez )
     
      ORD_SUFFIXES = {
        :plural => ["illionen", "illiarden"],
        :singular => ["illion", "illiarde"]
      }
     
      def self.zillion(n, plural)
        suffix = ORD_SUFFIXES[plural][(n % 6 == 0) ? 0 : 1]
        prefix = ORD_PREFIXES[n / 6]
        if prefix
          prefix + suffix
        end
      end
     
      PREFIXES = {
        1 => "ein",
        2 => "zwei",
        3 => "drei",
        4 => "vier",
        5 => "fünf",
        6 => "sechs",
        7 => "sieben",
        8 => "acht",
        9 => "neun"
      }
     
      SPECIALS = {
        0 => "null",
        1 => "eins",
        2 => "zwei",
        3 => "drei",
        4 => "vier",
        5 => "fünf",
        6 => "sechs",
        7 => "sieben",
        8 => "acht",
        9 => "neun",
        10 => "zehn",
        11 => "elf",
        12 => "zwölf",
        16 => "sechzehn",
        17 => "siebzehn",
        20 => "zwanzig",
        30 => "dreißig",
        60 => "sechzig",
        70 => "siebzig"
      }
     
      def self.int2cardinal(i)
        if i < 0
          return "minus " + int2cardinal(-i)
        elsif SPECIALS[i]
          return SPECIALS[i]
        elsif i >= 10**66
          return "ziemlich groß"
        end
     
        einer = i % 10
        zehner = i / 10
        hunderter = i / 100
        tausender = i / 1000
     
        case i
          when 13..19
            int2cardinal(einer) + "zehn"
          when 20..99
            if einer == 0
              int2cardinal(zehner) + "zig"
            else
              PREFIXES[einer] + "und" + int2cardinal(zehner*10)
            end
          when 100..999
            rest = i - (hunderter*100)
            if rest == 0
              PREFIXES[hunderter] + "hundert"
            else
              int2cardinal(hunderter*100) + int2cardinal(rest)
            end
          when 1_000..999_999
            rest = i - (tausender*1_000)
            if rest == 0
              if tausender < 10
                PREFIXES[tausender] + "tausend"
              else
                int2cardinal(tausender).sub(/eins$/, "ein") + "tausend"
              end
            else
              int2cardinal(tausender*1_000) + int2cardinal(rest)
            end
          else
            n = 6
            n += 3 while i / 10**n >= 1000
            components = []
            while n >= 6
              count = (i % 10**(n+3)) / 10**n
              if count == 0
                n -= 3
                next
              elsif count == 1
                components << "eine"
                components << zillion(n, :singular)
              else
                components << int2cardinal(count).sub(/eins$/, "ein")
                components << zillion(n, :plural)
              end
              n -= 3
            end
            if i % 1_000_000 != 0
              components << int2cardinal(i % 1_000_000)
            end
            components.join(" ")
        end
      end
     
      ###
      # Cardinal to integer
      ###
     
      R_2TO9 = /(zwei|drei|vier|fünf|sechs|sieben|acht|neun)/
      R_PRE = /(ein)|#{R_2TO9}/
      R_1TO9 = /(eins)|#{R_2TO9}/
      R_ZIG = /(drei)(ßig)|(zwan|vier|fünf|sech|sieb|acht|neun)(zig)/
      R_10TO19 = /(zehn|elf|zwölf)|(drei|vier|fünf|sech|sieb|acht|neun)(zehn)/
      R_20TO99 = /(?:#{R_PRE}(und))?#{R_ZIG}/
      R_1TO99 = /#{R_1TO9}|#{R_10TO19}|#{R_20TO99}/
      R_100TO999 = /#{R_PRE}(hundert)(?:#{R_1TO99})?/
      R_1TO999 = /#{R_1TO99}|#{R_100TO999}/
      R_NUMERAL = /^(?:(null)|#{R_1TO999})$/
     
      TOKEN_TO_INT = {
        "null"   => 0,
        "ein"    => 1,
        "eins"   => 1,
        "zwei"   => 2,
        "zwan"   => 2,
        "drei"   => 3,
        "vier"   => 4,
        "fünf"   => 5,
        "sech"   => 6,
        "sechs"  => 6,
        "sieb"   => 7,
        "sieben" => 7,
        "acht"   => 8,
        "neun"   => 9,
        "zehn"   => 10,
        "elf"    => 11,
        "zwölf"  => 12,
      }
     
      ORD_PREFIX_TO_EXP = Hash[*ORD_PREFIXES.zip((0..10).map{|n|n*6}).flatten]
     
      def self.zillion2int(z)
        m = z.match(/^(.+?)(illi(?:on(?:en)?|arden?))$/) or return nil
        exp = ORD_PREFIX_TO_EXP[m[1]] or return nil
        exp += 3 if m[2] =~ /^illia/
        10**exp
      end
     
      def self.cardinal2int(num)
        parts = num.strip.split(/\s+|(tausend)/)
     
        if parts[0] == "minus"
          factor = -1
          parts.shift
        else
          factor = 1
        end
     
        return nil if parts.empty?
     
        if parts.size == 1
          return sub1000cardinal2int(parts[0])
        end
     
        result = 0
        mult = nil
        parts.each_slice(2) do |num, ord|
          # Special cases for 1
          return nil if num =~ /eins$/ && !ord.nil?
          if (ord == "tausend" && num == "ein") ||
             (ord != "tausend" && num == "eine")
            value = 1
          else
            value = sub1000cardinal2int(num.sub(/ein$/, "eins")) or return nil
          end
          # Determine new multiplicator
          if ord.nil?
            new_mult = 1
          elsif ord == "tausend"
            new_mult = 1000
          else
            return nil if ord =~ /en$/ && value == 1
            new_mult = zillion2int(ord) or return nil
          end
          # Is this multiplicator lower than the last one?
          return nil if !mult.nil? && new_mult >= mult
          mult = new_mult
          # Finally update the result with the obtained value
          result += value*new_mult
        end
        factor * result
      end
     
      def self.sub1000cardinal2int(num)
        # Lexing
        m = R_NUMERAL.match(num) or return nil
     
        # Parsing
        tokens = m.to_a[1..-1].compact
        result = 0
        memo = 0
        tokens.each do |token|
          case token
            when "hundert"
              result += memo*100
              memo = 0
            when "zig", "ßig"
              result += memo*10
              memo = 0
            when "und"
              result += memo
              memo = 0
            else
              memo += TOKEN_TO_INT[token]
          end
        end
        result + memo
      end
     
    end # module GermanCardinals
     
    if __FILE__ == $0
      while x = ARGV.shift
        x = x.strip
        if x =~ /^-?\d+$/
          i = x.to_i
          cardinal = GermanCardinals::int2cardinal(i)
        else
          i = GermanCardinals::cardinal2int(x)
          cardinal = x
        end
        if i && cardinal
          puts "#{i}\t#{cardinal}"
        else
          puts "#{x}: Wie bitte?"
        end
      end
    end

    Beispielaufruf:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    $ ./german_cardinals.rb 12345678 "zwei Septilliarden zwölf Millionen dreihunderttausendfünf" zweiundvierzig zwölfunddreißig "eine Million zwei Milliarden" "ein Million" "ein Millionen" "eine Million"
    12345678    zwölf Millionen dreihundertfünfundvierzigtausendsechshundertachtundsiebzig
    2000000000000000000000000000000000000012300005  zwei Septilliarden zwölf Millionen dreihunderttausendfünf
    42  zweiundvierzig
    zwölfunddreißig: Wie bitte?
    eine Million zwei Milliarden: Wie bitte?
    ein Million: Wie bitte?
    ein Millionen: Wie bitte?
    1000000 eine Million
    Wie man sieht, habe ich die Umwandlung von Kardinal- in Dezimalzahlen sehr strikt gemacht. Nach „Millionen“ dürfen z.B. keine „Milliarden“ mehr kommen, „ein Million“ und „eine Millionen“ sind nicht zulässig etc. Das ist auch gut so, sonst lernen die Na'vi noch falsche Kardinalzahlen

    \edit: Fehler behoben und kompatibel zu Ruby 1.9 gemacht.

    Grüße,
    Matthias
    Angehängte Dateien Angehängte Dateien
    Geändert von Matthias Reitinger (17.01.10 um 18:37 Uhr)
     
    „Gib einem Menschen einen Fisch, und er wird für einen Tag satt. Lehre ihn Fischen, und er wird ein Leben lang satt.“
    “For every complex problem, there is an answer that is short, simple and wrong.”
    “Pessimism is safe, but optimism is a lot faster!”


    Aktuelles Coding Quiz: #17 - Wörter kreuz und quer

Thema nicht erledigt

Ähnliche Themen

  1. [QUIZ#14] Matthias Reitinger (Ruby)
    Von Matthias Reitinger im Forum Archiv
    Antworten: 3
    Letzter Beitrag: 28.03.10, 14:19
  2. [QUIZ#12] Matthias Reitinger (Ruby)
    Von Matthias Reitinger im Forum Archiv
    Antworten: 0
    Letzter Beitrag: 14.11.09, 17:15
  3. [QUIZ#10] Matthias Reitinger (Ruby)
    Von Matthias Reitinger im Forum Archiv
    Antworten: 1
    Letzter Beitrag: 10.10.09, 20:56
  4. [QUIZ#1] Matthias Reitinger (C++)
    Von Matthias Reitinger im Forum Archiv
    Antworten: 4
    Letzter Beitrag: 22.09.08, 22:02
  5. [QUIZ#1] Matthias Reitinger (Ruby)
    Von Matthias Reitinger im Forum Archiv
    Antworten: 0
    Letzter Beitrag: 21.09.08, 02:44