Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - for-in-Schleife


noo.bee - So 13.06.10 16:45
Titel: for-in-Schleife
folgende überlegung habe ich:

ich habe in einem memo knapp 1000 zeilen mit zahlen belegt. gegeben werden die variablen a - f durch benutzereingaben in ein edit-feld.
jetzt soll jede memozeile geprüft werden, wie oft in ihr der inhalt des edit-feldes vorkommt

bsp:
memo.lines:
1 4 6 2 8 7 5
2 4 5 7 9
1 3 5

inhalt der edit.felder
feld1 "3"
feld2 "7"
feld3 "1"

alle edit-felder werden nun mit jeder memozeile nacheinander abgeglichen. das ergebnis wäre also:
1. memo.line: 2 (treffer)
2. memo.line: 1 (treffer)
3. memo.line: 2 (treffer)

meine for-in schleife würde dann so aussehen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm2.Button1Click(Sender: TObject);
var x1 : Integer;
begin

  for (a=strtoint(memo1.lines.text)) or (b=strtoint(memo1.lines.text))  or (c=strtoint(memo1.lines.text)) in Memo1.Lines do begin
  inc(x1);

end;


warum bekomme ich folgende fehler ?
erwartet: Bezeichner, aber ( erhalten
erwartet: END, aber DO erhalten
erwartet: ., aber ; erhalten <-- das verschwindet, sobald ich das "end;" lösche, welches ich doch aber bei jedem "begin" brauche, oder ?


ALF - So 13.06.10 16:55

Hi

Delphi-Quelltext
1:
2:
3:
4:
for (a:=strtoint(memo1.lines.text)) or (b:=strtoint(memo1.lines.text))  or (c:=strtoint(memo1.lines.text)) in Memo1.Lines do 
begin
 inc(x1)
end;


erst mal so gesehen :wink:
Gruss Alf


noo.bee - So 13.06.10 17:04

denk ich grad falsch ? wollte nix zuweisen sonder vergleichen, deshalb nur "=" statt ":="


ALF - So 13.06.10 17:18

Ich glaube vergleichen macht man mit if
In einer For schleife kanst du links nur was zuweisen also

Delphi-Quelltext
1:
2:
3:
4:
5:
For a := 1 to 100 do
begin
  if (a = 50or (a = 70then exit;
 
end;

Was anderes habe ich bis jetzt noch nicht gesehen
Ansonsten musst Du ne While schleife nehmen. Dort kanst Du auch vergleichen!
oder

Delphi-Quelltext
1:
2:
3:
4:
if (a=strtoint(memo1.lines.text)) or (b=strtoint(memo1.lines.text))  or (c=strtoint(memo1.lines.text)) in Memo1.Lines then
begin
  inc(x1);
end;


Gruss ALf


jaenicke - So 13.06.10 18:20

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
In einer For schleife kanst du links nur was zuweisen also
Falsch, seit den Spracherweiterungen mit Turbo Delphi / Delphi 2006 geht auch das:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var
  c: Char;
  MyString: string;
begin
  MyString := 'abc';
  for c in MyString do
    if c in ['1''3'then
      ...
Die Kombination wie oben verstehe ich allerdings nicht, man kann so "nur" alle Elemente einer Menge durchgehen, mehr nicht.


ALF - So 13.06.10 18:34

Sorry @user profile iconjaenicke Ich bezog dies auf

Delphi-Quelltext
1:
for (a=...) or (b=...)                    

Hab mich wieder mal blöd ausgedrückt :oops:
Gruss Alf


noo.bee - So 13.06.10 18:50

Zitat:
man kann so "nur" alle Elemente einer Menge durchgehen, mehr nicht.

wie lässt sich denn jede zeile durchsuchen und von jeder zeile das ergebnis ausgeben ? oder kann ich memo nur komplett durchsuchen und die gesamtsumme ausgeben lassen ? das wäre natürlich mächtig blöd :/


jaenicke - So 13.06.10 18:55

Die Frage ist vor allem, ob es grundsätzlich einstellige Zahlen sind oder auch mehrstellige vorkommen können.

Denn wenn es nur einstellig sein kann, dann reicht es zeichenweise zu arbeiten.


noo.bee - So 13.06.10 19:19

mhhh, es können zahlen von 1-99 vorkommen... also leider auch zweistellig


jaenicke - So 13.06.10 19:55

Dann würde ich bei der geringen Anzahl an Zeilen einfach den trivialen Weg ohne Optimierung gehen und in jeder Zeile mit Pos nach jeder Zahl suchen.

Dabei muss auch beachtet werden, dass in mehrstelligen Zahlen nicht Teile als eine Zahl erkannt werden. Dafür können zum Beispiel die Leerzeichen einbezogen werden.


noo.bee - Mo 14.06.10 17:27

ist POS nicht zur berechnung der position eines strings da ? versteh da nicht ganz, wie mir das bei meinem prob helfen soll :shock:


Tropby - Mo 14.06.10 20:29

Du kannst doch so suchen, ob die Zeichen (Zahlen) in der Zeile vorkommen. Wenn Pos größer 0 ist dann kommt er in der Zeile vor.


Delphi-Quelltext
1:
2:
3:
for i := 0 to Memo.Lines.Count - 1 do
  if(pos('1', Memo.Lines[I]) > 0)then
    inc(x);


Wenn jetzt eine Zahl aber öfters vorkommen kann in einer Zeile dann musst du das auch noch beachten.


noo.bee - Mo 14.06.10 21:02

also in den zeilen kommen keine zahlen doppelt vor. aber muss ich jetzt für a, b, c, d, e und f jedesmal


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var a, b, c, d, e, f, x1 : Integer;
var I: array[1..1000of integer;
begin
for a := 0 to Memo1.Lines.Count - 1 do
  if(pos('1', Memo1.Lines[I]) > 0)then
    inc(x1);
end;
schreiben ?


ZeitGeist87 - Mo 14.06.10 21:29

Meine Damen und Herren,
nach langer Zeit mal wieder ein (hoffentlich) sinnvoller Post von mir.

Du deklarierst dir ein Array of Integer.
Dieses ist dynamisch und entspricht der Länge der Zeilen deines Memos.


Delphi-Quelltext
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:
var meineTreffer: array of Integer;
   def_a, def_b, def_c, def_d, def_e, def_f: String;
   Treffer: Integer; //Ändert sich von Zeile zu Zeile;
   Zeile: String;
   i: Integer; //i = Zeilenläufer
begin;
 //Hier setzen wir die Länge des Arrays ersteinmal auf 0
 setlength(meineTreffer, 0);
 
 //Nun auf die Anzahl der Zeilen des Memos
 setlength(meineTreffer, meinMemo.Lines.Count);

 //Überschreiben der Trefferdefinitionen
 def_a:= edit_a.text;
 def_b:= edit_b.text;
 def_c:= edit_c.text;
 //...
 def_f:= edit_f.text;

 //Treffer auf 0 setzen
 Treffer:= 0;

 //Jetzt durchlaufen wir die Zeilen
 for i:= 0 to meinMemo.Lines.Count-1 do
 begin
  //Wir überschreiben (unnötigerweise) die MemoZeile in die Variable Zeile
  Zeile:= meinMemo.Lines[i];
 
  //Hier könnte noch eine Prüfung rein, ob die Länge der Zeile zulässig (> 0) ist
  //Machen wir doch direkt
  if length(Zeile) <= 0 then
  begin
   //meineTreffer schreiben mit 0, da Zeile leer ist und somit bedeutungslos
   meineTreffer[i]:= 0;
   continue; //und die nächste Zeile ranholen, ohne nachfolgenden Code auszuführen
  end;
 
  //Und nun korrekterweise mit pos() abfragen
  if pos(def_a, Zeile) then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  if pos(def_b, Zeile) then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  //...
  if pos(def_f, Zeile) then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);


  //Überschreiben der Treffer in die Trefferliste
  meineTreffer[i]:= Treffer;
  
  Treffer:= 0;
 end;

 //Glückwunsch!
 //An dieser Position wurden alle deine Zeilen abgearbeitet und auf Treffer überprüft.

 //Zur Ausgabe:
 //Einfach über deine Trefferliste meineTreffer eine Schleifen laufen lassen und den Wert ausgeben, der dahintersteht.
 for i:= low(meineTreffer) to high(meineTreffer) do
 begin
  //Memo leeren
  meinMemo.lines.clear;
  //Ausgabe
  meinMemo.lines.add('Zeile ' + inttostr(i+1) + ': ' + IntToStr(meineTreffer[i]) + ' Treffer');

  //Warum i+1 bei der Zeile?
  //Nun, du beginnst die Zeilen bei 1 zu zählen, Delphi bei 0 ;-)
 end;
end;


Geschafft. Ausm Kopf. Hoffentlich funktionstüchtig.

Guten Abend.
Stefan


noo.bee - Mi 16.06.10 18:22

huu, erstmal danke für die hilfe. habs mal durchgeackert. sieht soweit gut aus ausser dass

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
//Und nun korrekterweise mit pos() abfragen
  if <span style="color: orange">pos(def_a, Zeile)</span> then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  if <span style="color: orange">pos(def_b, Zeile)</span> then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  //...
  if <span style="color: orange">pos(def_f, Zeile)</span> then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

alle nicht boolean sind


Jakob_Ullmann - Mi 16.06.10 18:27

pos() gibt nur den Index des gesuchten Zeichens im String zurück. Du könntest schreiben if pos(...) > 0 then, denn wenn das Zeichen nicht vorkommt, ist pos() null.


ZeitGeist87 - Mi 16.06.10 18:27

user profile iconnoo.bee hat folgendes geschrieben Zum zitierten Posting springen:
huu, erstmal danke für die hilfe. habs mal durchgeackert. sieht soweit gut aus ausser dass

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
//Und nun korrekterweise mit pos() abfragen
  if <span style="color: orange">pos(def_a, Zeile)</span> then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  if <span style="color: orange">pos(def_b, Zeile)</span> then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  //...
  if <span style="color: orange">pos(def_f, Zeile)</span> then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

alle nicht boolean sind


Mea maxima culpa!

Natürlich ist die Rückgabe von pos() ein Integer.
Somit musst du prüfen if pos(def_a, zeile) > 0 then

Aber durch Lesen der Hilfe... :P


noo.bee - Mi 16.06.10 20:54

ja passt ;) habs durch probieren auch hinbekommen mit  > 0. aber leider spuckt er mir immer nur die treffer der letzten zeile aus :(


ZeitGeist87 - Mi 16.06.10 20:59

Magst du mal bitte deinen Code posten? ;-)


noo.bee - Mi 16.06.10 21:10

ist eig. dein funktionierender code. hab nur sachen geändert wie die richtigen edits oder memos und sowas


Delphi-Quelltext
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:
procedure TForm2.Button1Click(Sender: TObject);
var meineTreffer: array of Integer;
   def_a, def_b, def_c, def_d, def_e, def_f: String;
   Treffer: Integer; //Ändert sich von Zeile zu Zeile;
   Zeile: String;
   i: Integer; //i = Zeilenläufer
begin
 //Hier setzen wir die Länge des Arrays ersteinmal auf 0
 setlength(meineTreffer, 0);

 //Nun auf die Anzahl der Zeilen des Memos
 setlength(meineTreffer, Memo1.Lines.Count);

 //Überschreiben der Trefferdefinitionen
 def_a:= edit1.text;
 def_b:= edit2.text;
 def_c:= edit3.text;
 def_d:= edit4.text;
 def_e:= edit5.text;
 def_f:= edit6.text;

 //Treffer auf 0 setzen
 Treffer:= 0;

 //Jetzt durchlaufen wir die Zeilen
 for i:= 0 to Memo1.Lines.Count-1 do
 begin
  //Wir überschreiben (unnötigerweise) die MemoZeile in die Variable Zeile
  Zeile:= Memo1.Lines[i];

  //Hier könnte noch eine Prüfung rein, ob die Länge der Zeile zulässig (> 0) ist
  //Machen wir doch direkt
  if length(Zeile) <= 0 then
  begin
   //meineTreffer schreiben mit 0, da Zeile leer ist und somit bedeutungslos
   meineTreffer[i]:= 0;
   continue; //und die nächste Zeile ranholen, ohne nachfolgenden Code auszuführen
  end;

  //Und nun korrekterweise mit pos() abfragen
  if pos(def_a, Zeile) > 0 then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  if pos(def_b, Zeile) > 0 then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  if pos(def_c, Zeile) > 0 then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  if pos(def_d, Zeile) > 0 then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  if pos(def_e, Zeile) > 0 then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);

  if pos(def_f, Zeile) > 0 then
   //Kommt vor -> Treffer erhöhen
   inc(Treffer);


  //Überschreiben der Treffer in die Trefferliste
  meineTreffer[i]:= Treffer;

  Treffer:= 0;
 end;

 //Glückwunsch!
 //An dieser Position wurden alle deine Zeilen abgearbeitet und auf Treffer überprüft.

 //Zur Ausgabe:
 //Einfach über deine Trefferliste meineTreffer eine Schleifen laufen lassen und den Wert ausgeben, der dahintersteht.
 for i:= low(meineTreffer) to high(meineTreffer) do
 begin
  //Memo leeren
  Memo2.lines.clear;
  //Ausgabe
  Memo2.lines.add('Zeile ' + inttostr(i+1) + ': ' + IntToStr(meineTreffer[i]) + ' Treffer');

  //Warum i+1 bei der Zeile?
  //Nun, du beginnst die Zeilen bei 1 zu zählen, Delphi bei 0 ;-)
 end;
end;
end.


ZeitGeist87 - Mi 16.06.10 21:15

Entweder bin ich blind, blöd oder es liegt daran, dass ich seit heute Kontaktlinsen tragen: Ich finde gerade keinen Fehler.

Würde es dir was ausmachen, das Projekt anzuhängen und eine Datei?
Falls du es nicht öffentlich machen willst, gern auch per PN.

LG
Stefan

---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

Ganz einfach :)

Geh runter zur Ausgabe und such diese Zeilen


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
//Glückwunsch!
 //An dieser Position wurden alle deine Zeilen abgearbeitet und auf Treffer überprüft.

 //Zur Ausgabe:
 //Einfach über deine Trefferliste meineTreffer eine Schleifen laufen lassen und den Wert ausgeben, der dahintersteht.
 for i:= low(meineTreffer) to high(meineTreffer) do
 begin
  //Memo leeren
  Memo2.lines.clear;
  //Ausgabe
  Memo2.lines.add('Zeile ' + inttostr(i+1) + ': ' + IntToStr(meineTreffer[i]) + ' Treffer');

  //Warum i+1 bei der Zeile?
  //Nun, du beginnst die Zeilen bei 1 zu zählen, Delphi bei 0 ;-)
 end;


Du bist in einer Schleife und leerst bei jedem Durchlauf das Memo2 :)

Setz das .clear einfach vor die Schleife.

LG
Stefan


noo.bee - Mi 16.06.10 22:19

tja dann würde ich sagen, dass du das prob gelöst hast ;) DANKEEEEE


ZeitGeist87 - Mi 16.06.10 22:20

Da macht sich Erleichterung in mir breit und ich kann nun ruhigen Gewissens mich meinem Lesestoff widmen :)

Viel Spaß damit und gute Nacht.


noo.bee - Do 17.06.10 20:27

so, programm ausgiebig getestet ;) ABER ich habe folgendes festgestellt: der suchlauf berücksichtigt nicht, ob nach ein- oder zweistelligen zahlen gesucht werden sollen.

wenn ich also die zahlenkombi "1, 23, 4, 6, 11, 15, 19" nach der "1" durchsuche, müßte das ergebnis eigentlich 1 sein, da die "1" ja nur einmal drin ist. ich bekomm aber das ergebnis "5" wegen der "11" und der "15" und der "19".


ZeitGeist87 - Do 17.06.10 20:51

Da hast du recht :)
Du könntest eine StringList einbauen, den Delimiter auf Leerzeichen stellen und die Zeile so aufsplitten lassen.
Dann musst du die StringList durchgehen und hättest das Problem gelöst.

Anderer Ansatz: Du prüfst, ob vor oder nach der Position ein Leerzeichen ist. Wenn ja, erhöhen ansonsten ignorieren.
Pass aber auf, wenn du ganz am Anfang bei jeder Zeile bist.
String geht bei 1 los. 1-1 (davor) = 0 = Zugriffsverletzung.

LG
Stefan


noo.bee - Do 17.06.10 20:58

was, wie ? nochmal für mich zum mitschreiben... also ich versteh beide möglichkeiten nicht :( hast noch eine, die ich auch hinbekomm :wink:


ZeitGeist87 - Do 17.06.10 21:15

Entschuldige. :)

Ich würde dir die zweite Möglichkeit ans Herz legen.

Im Moment haben wir es so *Ich such mal den Quelltext*
Ah.
Wir suchen einfach mit pos() das Vorkommen der Zahl, unabhängig davon, ob ein- oder zweistellig.

Ich würde vorschlagen, wir basteln jetzt einfach eine Funktion, die uns die Arbeit abnimmt. Vorteil: Einmal etwas Aufwand und dann nur eine Zeile :)


Delphi-Quelltext
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:
function checkVorkommen(Zeile, Zahl: String): Boolean;
var _pos: Integer; //Hier speichern wir die Position unseres Fundes
    _len: Integer; //Länge der Zeile (in Zeichen)
begin;
 try
  //Rückgabe undefiniert (false)
  result:= false;
  
  _pos:= pos(Zahl, Zeile);
  _len:= length(Zeile);

 case _pos of
  1:     begin
          //Zeichen an erster Stelle, nachfolgendes Zeichen muss Leerzeichen sein, verschoben und lenght(Zahl);
          //Natürlich darf Zeile[_pos+length(Zahl)] die length(Zeile) nicht übersteigen
          if (_pos+length(Zahl)) <= _len then
          begin 
           //Hier auf Leerzeichen prüfen
           if not (Zeile[_pos+length(Zahl)] = #32then
            exit; //Wegwerfen, da ungültig
          end;
         end;
  else
  begin
   //Und hier der Spezialfall: Mitten in der Zeichenkette

   if _pos-1 < 1 then
    exit; //String[0] geht nicht

   if _pos = _len then
   begin
    //hier müssen wir nur einen Schritt nach "links" gehen und schon muss da ein Leerzeichen sein
    if Zeile[_pos-1] <> #32 then
     exit; //Doch keins -> Abbruch
   end;

   if _pos+length(Zahl) <= _len then
   begin
    //Hier schießen wir über kein Ziel hinaus
    if (Zeile[_pos-1] <> #32or
       (Zeile[_pos+length(Zahl)] <> #32then
     exit; //Mittendrin, aber links und rechts kein Leerzeichen
   end
   else
   begin
    //Hier nur davor
    if Zeile[_pos-1] <> #32 then
     exit;
   end;
  end;
 end;
  

  //Verarbeitung erfolgreich
  result:= true;
 except
  on e: exception do
   messagebox(application.handle, pchar(e.message), pchar('Fehler'), MB_IconERROR);
 end;
end;



Im bisherigen Quelltext entfallen die Zeilen if pos(def_a, zeile) > 0 then und werden durch

Delphi-Quelltext
1:
2:
 if checkVorkommen(Zeile, def_a) then
 inc(Treffer);
ersetzt.

Ich hoffe, ich hab es ohne Logikfehler getippt.

LG
Stefan

Edit: Zur Sicherheit bau ich mir schnell ein Testprogramm

Edit die Zweite: Bekannter Bug: Da immer nur das erste Vorkommende Zeichen relevant ist, werden spätere, einstellige in der gleichen Zeile nicht gefunden.

Bsp.: 45 36 8 3 6 und nach 6 wird gesucht: Findest Position 4, ist aber fehlerhaft, da davor kein Leerzeichen. 6 an letzter Position wird nicht mehr gefunden.
Wie kompensieren: An entsprechender Stelle einen weiteren pos()-Aufruf in einem REPEAT...UNTIL suchpos = _len;


noo.bee - Fr 18.06.10 18:14

bekannter bug ? also bei mir läufts ohne prob. oder hab ich den fehler nicht gefunden ?
ich hab nirgends "An entsprechender Stelle einen weiteren pos()-Aufruf in einem REPEAT...UNTIL suchpos = _len;" eingefügt

EDIT: doch n fehler gefunden. schau mal auf den screenshot. warum hab ich in zeile 1 keinen treffer ? dort wäre doch die "1" vorhanden :/


ZeitGeist87 - Fr 18.06.10 18:24

Ist mir gestern aufgefallen, als ich das Testprogramm schnell geschrieben hab.

Wie gesagt, nimm meine Zahlenreihe: {code]45 36 8 3 6[/code]

Füg in def_a (edit1.text) 6 ein und die restlichen Felder 0 oder leer lassen.
Klick auf auswerten.

Wir rutschen dann in die Routine des Auswertens herein und dort passiert folgendes.

Über pos('6''45 36 8 3 6') wird die Position 5 ausgegeben, da die 6 das erste Mal bei 36 auftaucht.
Nun ist diese Position mitten in der Zeichenkette und es wird geprüft, ob davor und danach ein Leerzeichen ist. Ist jedoch nicht der Fall, also kein Treffer.

Und genau da müsste die zeichenweite Suche ansetzen, dass du den String von der gefundenen Stelle bis zum Schluss durchläufst, um wirklich sicher zu sein :)

Das ist der Bug.

Zu deinem Edit: Ich tipp es mal bei mir ein und analysier :)


ZeitGeist87 - Fr 18.06.10 18:31

Konnte keinen Fehler feststellen.

Screenshot anbei