strip, split - mehrere Argumente

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Yuzuke
User
Beiträge: 10
Registriert: Dienstag 6. Juli 2010, 12:38

Freitag 9. Juli 2010, 17:11

Hallo,

ich möchte die Zeichenkette "3V4+3" oder "2V1-5" aufteilen, dass ich jeweils die Zahlen in einer Liste habe. Im ersten Fall möchte ich also Liste[3,4,3] im zweiten Liste=[2,1,5]. Das ganze habe ich mit strip und split versucht, allerdings geht das nicht. Was soll ich machen?
lunar

Freitag 9. Juli 2010, 17:15

Was Du erst mal machen sollst, ist uns sagen, wie Dein Versuch aussah, und was nicht funktioniert hat ;)

In einem Schritt lässt sich das mit ".split()" und ".strip()" eh nicht trennen. Das würde nur mit einem regulären Ausdruck und "re.split" funktionieren.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Freitag 9. Juli 2010, 17:54

Dein Problem könnte man gut mit einer List Comprehension lösen:

Code: Alles auswählen

>>> l = ['3V4+3', '2V1-5']
>>> [[c for c in item if c.isdigit()] for item in l]
[['3', '4', '3'], ['2', '1', '5']]
the more they change the more they stay the same
karolus
User
Beiträge: 100
Registriert: Samstag 22. August 2009, 22:34

Freitag 9. Juli 2010, 19:52

Hallo

Code: Alles auswählen

import re
vstring = "3V4+3"
re.findall( "\d+" , vstring)
Gruß Karo
Yuzuke
User
Beiträge: 10
Registriert: Dienstag 6. Juli 2010, 12:38

Samstag 10. Juli 2010, 09:05

Hmm, danke für eure Hilfe. Ich habe gerade gemerkt, dass es noch ein wenig komplizierter ist.

Folgende Formen kann das ganze nämlich annehmen:
2V17+3
5V2
12V8-3
19V19+100

Die Zahlen können also beliebe Werte annehmen, während der Teil mit + und - zuzüglich der Zahl danach nicht vorkommen muss, aber kann. Außerdem muss ich schon wissen, ob es sich um ein + oder - handelt. Wenn ich re.findall( "\d+" , vstring) benutze, bekomme ich ja nur die Zahlen, + und - aber nicht. Wenn ich [c for c in vstring] benutze, habe ich allerdings keine Ahnung wo sich das + oder - befindet (kann ja an unterschiedlichen Stellen sein, da die Zahlen unterschiedlich lang sein können) und ich kann dann nicht z.B. if Variable[3] == "+": abfragen.
karolus
User
Beiträge: 100
Registriert: Samstag 22. August 2009, 22:34

Samstag 10. Juli 2010, 09:19

Hallo

Code: Alles auswählen

re.findall("(?:\+|-)?\d+", vstring)
Gruß Karo
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Samstag 10. Juli 2010, 09:19

Yuzuke hat geschrieben:Folgende Formen kann das ganze nämlich annehmen:
2V17+3
5V2
12V8-3
19V19+100
Könntest du erklären, was das ist?
Diese Beispiele kann man ja noch mit regex abdecken: "(\d+)V(\d+)([+-]\d+)?" (ungestet)

hth, Jörg
ps.: Sind 'verbose'-Regex viel besser lesbar?

Code: Alles auswählen

r"""(?x)    #verbose regex
    (       #Neue Gruppe
      \d+   #mehr als 1 Ziffer
    )       # 1. Gruppe (<matchobject>.group(1)
    V       # ein 'V'
    (
      \d+
    )       # 2. Gruppe
    (
      [+-] # '+' oder '-'
      \d+
    )?      # 3. Gruppe, ist optional
    """
edit: regex vereinfacht, ps geschrieben
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Samstag 10. Juli 2010, 09:45

Eigentlich ist das doch eine schöne Übung und auch kein Hexenwerk.
Du legst eine leere Liste an. Dann iterierst Du über den String. Wenn das aktuelle Zeichen ein Digit ist fügst Du es einem aktuellen Ziffernstring hinzu. Wenn dann mal was anderes als eine Ziffer kommt, hängst Du diesen einfach an die Liste an. Mal ausprobieren. Es ist viel schöner, wenn man ein Problem selbst geknackt hat. Wenn's hakt gibt es sicher genügend, die weiterhelfen können.
In der Snippets Sektion gibt es ausserdem auf der zweiten Seite ganz oben ein paar Beispiele zu einem ähnlich gestrickten Problem.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Samstag 10. Juli 2010, 11:56

b.esser-wisser hat geschrieben:ps.: Sind 'verbose'-Regex viel besser lesbar?
Nein. Ich finde die kompakte Form übersichtlicher. Aber das war wohl eine rhetorische Frage, oder?

Stefan
lunar

Samstag 10. Juli 2010, 12:13

sma hat geschrieben:
b.esser-wisser hat geschrieben:ps.: Sind 'verbose'-Regex viel besser lesbar?
Nein. Ich finde die kompakte Form übersichtlicher.[/quote]
Naja, es kommt irgendwo auch auf die Komplexität des Ausdrucks an ...
Zuletzt geändert von lunar am Sonntag 11. Juli 2010, 11:02, insgesamt 1-mal geändert.
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Samstag 10. Juli 2010, 13:50

Mann kann sich ja auch eine nicht kommentierte RE kommentieren lassen:

Code: Alles auswählen

>>> re.compile("(?:\+|-)?\d+", re.DEBUG)
max_repeat 0 1
  subpattern None
    in
      literal 43
      literal 45
max_repeat 1 65535
  in
    category category_digit
Yuzuke
User
Beiträge: 10
Registriert: Dienstag 6. Juli 2010, 12:38

Montag 19. Juli 2010, 11:54

Hallo,

danke an alle, ich habe es jetzt hinbekommen wenn auch nicht mit RegEx, sondern mit der Standardfunktion find(). Da sich nochmal ein paar Sachen geändert haben und falls vllt. andere an dieser Lösung interessiert sind poste ich sie mal:

Code: Alles auswählen

        String = "2W6+5"
        Damage = 0

        if String.find("+") >= 0:
            Modifier = "+"
            Until = String.find("+")
            Left = String[0:Until]
            Number = int(String[Until+1:])
            String = String[0:Until]
        elif String.find("-") >= 0:
            Modifier = "-"
            Until = String.find("-")
            Left = String[0:Until]
            Number = int(String[Until+1:])
            String = String[0:Until]
        else:
            Modifier = None

        Until = String.find("W")
        Counter = int(String[0:Until])
        Dice = int(String[Until+1:])

        for i in range(Counter):
            Damage += random.randint(1,Dice)

        if Modifier is not None:
            if Modifier == "+":
                Damage += Number
            if Modifier == "-":
                Damage -= Number

        if Damage < 0:
            Damage = 0
        
        return Damage
Zur Erklärung: In einem Spiel namens Midgard wird der Schaden, den ein Held anrichtet auf die oben beschriebene Weise beschrieben. 2W6+5 bedeutet nichts anderes als 2 mal mit einem 6 seitigem Würfel zu würfeln und 5 zu addieren - fertig ist der Schaden. Genau das soll mein Code abarbeiten. Ich weiß ich bin ein Python Anfänger und es gibt sicherlich bessere Möglichkeiten aber so geht's doch, oder?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7477
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Montag 19. Juli 2010, 12:01

Alternativ kann man ggf. auch das benutzen: http://code.google.com/p/dyce/

Ich würde bei dieser simplen Form wohl auch mit einem RegExp arbeiten.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Trichter
User
Beiträge: 45
Registriert: Montag 20. April 2009, 10:21

Montag 19. Juli 2010, 13:26

Zufällig komme ich auch aus der RPG Ecke und hab da was für dich:

Code: Alles auswählen

import random

def roll_dice(a,b):
    result = 0
    for i in range(a):
        result += random.randint(1,b)
    return result

def eval_number(input_string):
    try:
        result = int(input_string)
    except ValueError:
        dice_list = input_string.split("W")
        result = roll_dice(int(dice_list[0]), int(dice_list[1]))
    return result

def eval_term(input_string):
    input_string.strip()
    result = 0
    plus_list = input_string.split('+')
    for p_term in plus_list:
        minus_list = p_term.split('-')
        # evaluate first term of minus_list
        result += eval_number(minus_list[0])
        # evaluate other terms of minus list
        for i in range(1, len(minus_list)):
            result -= eval_number(minus_list[i])
    return max(result, 0)

test = ["2W6+3", "5-3", "18W20-5", "5+3-8", "1W6-12"]
for element in test:
    print eval_term(element)
Benutzeravatar
pillmuncher
User
Beiträge: 1164
Registriert: Samstag 21. März 2009, 22:59
Wohnort: München

Montag 19. Juli 2010, 17:04

Zum Spaß:

Code: Alles auswählen

import re
import random
import operator

class Bunch(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

match = re.compile(
    flags = re.VERBOSE,
    pattern = r"""
        (?P<times> \d+ )
        (?P<item> [A-Z] )
        (?P<sides> \d+ )
        ( (?P<op> \+ | \- ) (?P<value> \d+ ) | $ )
        | (?P<error> .* )
    """
).match

ops = {'+':operator.add, '-':operator.sub, None:operator.add}

def damage(raw):
    parsed = Bunch(**match(raw).groupdict())
    if parsed.error:
        raise ValueError('Invalid argument "%s"' % parsed.error)
    times = int(parsed.times)
    sides = int(parsed.sides)
    value = int(parsed.value or 0)
    op = ops[parsed.op]
    return max(0, op(sum(random.randint(1, sides) for each in xrange(times)), value))


print damage('2W6+5')
print damage('1W6-7') # immer 0
print damage('2V17+3')
print damage('5V2')
print damage('12V8-3')
print damage('19V19+100')
print damage('hallo ich bin kaputt!!!')
Gruß,
Mick.
Zuletzt geändert von pillmuncher am Dienstag 20. Juli 2010, 00:50, insgesamt 2-mal geändert.
In specifications, Murphy's Law supersedes Ohm's.
Antworten