Gleich weg damit _ArrayDelete($Array, 0) und UBound verwenden!
Die Anzahl in Index 0 ist doch sowieso eine Unsitte.
Beiträge von Oscar
-
-
For $i = $aArray[0] To 1 Step -1
If StringLeft($Array[$i][1], 1) = "s" ThenEinmal ein Eindimensionales Array ($aArray) und einmal ein zweidimensionales Array ($Array) und dann auch noch unterschiedliche Namen.
Vielleicht solltest Du Dich erstmal mit den Grundlagen von AutoIt beschäftigen.
Oder eine Beispieldatei posten, damit man Dir vernünftig helfen kann. -
Mit allen Optimierungen (das mit ENTIRESPLIT hat mich überrascht) bei beiden Funktionen, sind sie nahezu gleichauf (120ms weniger bei der New-Variante).
Dafür ist Deine Funktion universeller (wegen automatischer Anpassung der 2. Dimension):AutoIt
Alles anzeigen#include <Array.au3> Global $s_String = BinaryToString(InetRead("https://pastebin.com/raw/w3SgtP9Q")) Global $iTimer = TimerInit() For $i = 0 To 99 $a_Splitted = _StringSplit2D($s_String) Next ConsoleWrite(TimerDiff($iTimer) & @CR) _ArrayDisplay($a_Splitted) Global $iTimer = TimerInit() For $i = 0 To 99 $a_Splitted = _NewStringSplit2D($s_String) Next ConsoleWrite(TimerDiff($iTimer) & @CR) _ArrayDisplay($a_Splitted) Func _StringSplit2D(ByRef $s_String, $sDelim = @CR, $sDelim2 = ",", $i_Start = 0) Local $a_FirstDim = StringSplit($s_String, $sDelim, 3) Local $a_Out[UBound($a_FirstDim)][1], $a_Line, $i_2DMax = 1 For $i = $i_Start To UBound($a_FirstDim) - 1 $a_Line = StringSplit($a_FirstDim[$i], $sDelim2, 3) If UBound($a_Line) > $i_2DMax Then $i_2DMax = UBound($a_Line) ReDim $a_Out[UBound($a_Out)][$i_2DMax] EndIf For $j = 0 To UBound($a_Line) - 1 $a_Out[$i][$j] = $a_Line[$j] Next Next Return $a_Out EndFunc ;==>_StringSplit2D Func _NewStringSplit2D(ByRef $s_String, $sDelim = @CR, $sDelim2 = ",", $i_Start = 0) Local $a_FirstDim = StringSplit($s_String, $sDelim, 3) StringReplace($a_FirstDim[$i_Start], $sDelim2, $sDelim2, 0, 1) Local $iSecondDim = @extended + 1, $a_Out[UBound($a_FirstDim)][$iSecondDim], $a_Line For $i = $i_Start To UBound($a_FirstDim) - 1 $a_Line = StringSplit($a_FirstDim[$i], $sDelim2, 3) For $j = 0 To UBound($a_Line) - 1 $a_Out[$i][$j] = $a_Line[$j] Next Next Return $a_Out EndFunc ;==>_NewStringSplit2DIch denke, dass ich mich geschlagen gebe und Deine Funktion als Gewinner darstelle.

-
Ich bin halt auch davon ausgegangen, dass einige Zeilen weniger enthalten können als andere.
Wenn z.B. die erste Zeile nur 5 Elemente hat und alle anderen 7.Ah, ok! Wenn die Daten in der zweiten Dimension eine unterschiedliche Anzahl an Elementen aufweisen, dann lieber so, wie von Dir vorgeschlagen.
Und: ja, StringReplace und @extended ist noch etwas schneller als StringSplit:
AutoIt
Alles anzeigenFunc _NewStringSplit2D(ByRef $sString, $sDelim = @CR, $sDelim2 = ",", $i_Start = 0) Local $a_FirstDim = StringSplit($s_String, $sDelim, 2) Local $tmp = StringReplace($a_FirstDim[$i_Start], $sDelim2, ''), $iSecondDim = @extended + 1 Local $a_Out[UBound($a_FirstDim)][$iSecondDim] , $a_Line For $i = $i_Start To UBound($a_FirstDim) - 1 $a_Line = StringSplit($a_FirstDim[$i], $sDelim2, 2) For $j = 0 To UBound($a_Line) - 1 $a_Out[$i][$j] = $a_Line[$j] Next Next Return $a_Out EndFunc ;==>_NewStringSplit2D
Und es ist auch gar nicht das eine ReDim, was zu der kürzeren Laufzeit führt, sondern das fehlen der If-Anweisung innerhalb der For...Next-Schleife. -
Ein ReDim würde nur erfolgen wenn eine Zeile mehr Elemente hat als bisherige.
Im konkreten Beispiel also nur ein einziges mal - das ist verkraftbar.Stimmt! So benötigt man nur ein ReDim.
Es geht aber auch ganz ohne ReDim, indem man ein zusätzliches StringSplit einfügt:AutoIt
Alles anzeigenFunc _NewStringSplit2D(ByRef $sString, $sDelim = @CR, $sDelim2 = ",", $i_Start = 0) Local $a_FirstDim = StringSplit($s_String, $sDelim, 2) Local $a_Line = StringSplit($a_FirstDim[$i_Start], $sDelim2, 2) Local $a_Out[UBound($a_FirstDim)][UBound($a_Line)] For $i = $i_Start To UBound($a_FirstDim) - 1 $a_Line = StringSplit($a_FirstDim[$i], $sDelim2, 2) For $j = 0 To UBound($a_Line) - 1 $a_Out[$i][$j] = $a_Line[$j] Next Next Return $a_Out EndFunc ;==>_NewStringSplit2D
Das zusätzliche StringSplit ist auch etwas schneller als das ReDim. Wobei sich das erst bei mehreren Durchläufen bemerkbar macht:AutoIt
Alles anzeigen#include <Array.au3> Global $s_String = BinaryToString(InetRead("https://pastebin.com/raw/w3SgtP9Q")) Global $iTimer = TimerInit() For $i = 0 To 99 $a_Splitted = _StringSplit2D($s_String) Next ConsoleWrite(TimerDiff($iTimer) & @CR) _ArrayDisplay($a_Splitted) Global $iTimer = TimerInit() For $i = 0 To 99 $a_Splitted = _NewStringSplit2D($s_String) Next ConsoleWrite(TimerDiff($iTimer) & @CR) _ArrayDisplay($a_Splitted) Func _StringSplit2D(ByRef $sString, $sDelim = @CR, $sDelim2 = ",", $i_Start = 0) Local $a_FirstDim = StringSplit($s_String, $sDelim, 2) Local $a_Out[UBound($a_FirstDim)][1] Local $a_Line, $i_2DMax = 1 For $i = $i_Start To UBound($a_FirstDim) - 1 $a_Line = StringSplit($a_FirstDim[$i], $sDelim2, 2) If UBound($a_Line) > $i_2DMax Then $i_2DMax = UBound($a_Line) ReDim $a_Out[UBound($a_Out)][$i_2DMax] EndIf For $j = 0 To UBound($a_Line) - 1 $a_Out[$i][$j] = $a_Line[$j] Next Next Return $a_Out EndFunc ;==>_StringSplit2D Func _NewStringSplit2D(ByRef $sString, $sDelim = @CR, $sDelim2 = ",", $i_Start = 0) Local $a_FirstDim = StringSplit($s_String, $sDelim, 2) Local $a_Line = StringSplit($a_FirstDim[$i_Start], $sDelim2, 2) Local $a_Out[UBound($a_FirstDim)][UBound($a_Line)] For $i = $i_Start To UBound($a_FirstDim) - 1 $a_Line = StringSplit($a_FirstDim[$i], $sDelim2, 2) For $j = 0 To UBound($a_Line) - 1 $a_Out[$i][$j] = $a_Line[$j] Next Next Return $a_Out EndFunc ;==>_NewStringSplit2D -
also brauche ich gar kein ReDim?
Stell mal eine Beispiel-Datei (muss keine 3000 Zeilen enthalten) zur Verfügung, dann kann ich Dir zeigen, wie das gemeint ist.
-
Ich verstehe bei der Aufgabenstellung nicht, wieso überhaupt das ReDim gebraucht wird.
Mit StringSplit die Zeilen splitten, somit kennt man die erste Dimension. Anschließend erstmal eine Zeile nach Spalten splitten und man kennt die zweite Dimension.
Damit kann man das Ausgabe-Array dimensionieren und die Daten dort hineinkopieren. -
StringInStr
Ich denke, Du meinst eher: StringReplace.
-
Die Verben richten sich nach dem was in der Registry hinterlegt ist.
Hier wird eine .exe aufgerufen. Unter HKCR\.exe finden wir den Verweis wo die Eintragungen zu finden sind was ShellExecute mit .exe-Dateien alles anfangen kann.
In dem Fall also unter HKCR\exefile. Dort finden sich unter HKCR\exefile\Shell alle Verben die bei exe-Dateien verwendet werden können. Unter anderem auch das ominöse runas. Das Aufrufkommando unterscheidet sich hierbei nicht von "open" aber interessant ist der gesetzte Wert HasLUAShield. Wenn der gesetzt ist kommt für das Kommando vorher die UAC-Abfrage.Zum ersten mal bin ich vor einigen Jahren auf das HasLUAShield gestoßen als ich eine Lösung gesucht habe um Admin-Rechte in einer Batch-Datei zu erzwingen.
Ok! Vielen Dank für die Erklärung!
Diesen Trick werde ich mir auf jeden Fall archivieren. Das kann ich bestimmt mal gebrauchen.
-
Edit: Geht ja noch viel einfacher:
Upps! Das funktioniert ja wirklich!
Wobei: Auf einem x64-System braucht man noch: #AutoIt3Wrapper_UseX64=y am Anfang, sonst stimmt der Pfad zu hosts nicht.
Aber woher hast Du das "runas"?
Das steht gar nicht in der Hilfe und unter MSDN findet man das auch nicht. -
ansonsten geht da ein Mod/Admin ran.
Soeben passiert!
-
Edit: ein Sleep() ist nicht notwendig in der Schleife?
Du kannst da noch ein Sleep(10) oder so einbauen, damit die Prozessorlast niedrig bleibt.
-
Ich würde zusätzlich einen Timeout einbauen, für den Fall, dass das Fenster nicht aufgeht:
AutoIt
Alles anzeigen$iTimer = TimerInit() Do $sTitle = _Process2Win("calc.exe") Until $sTitle <> -1 Or TimerDiff($iTimer) > 3000 MsgBox(0, "", $sTitle) Func _Process2Win($pid) If IsString($pid) Then $pid = ProcessExists($pid) If $pid = 0 Then Return -1 Local $list = WinList(), $wpid For $i = 1 To $list[0][0] If $list[$i][0] <> "" AND BitAnd(WinGetState($list[$i][1]),2) Then $wpid = WinGetProcess($list[$i][0]) If $wpid = $pid Then Return $list[$i][0] EndIf Next Return -1 EndFunc -
Ich plane alle meine GUIs (mehr oder weniger) im Kopf.
Meist setze ich die Control-Elemente erstmal irgendwo (so grob) auf die GUI und schaue dann, wie es aussieht.
Wenn es mir nicht gefällt, dann werden die Werte (Left, Top, Width, Height) eben so lange geändert, bis es passt.
Das mag der Ein oder Andere als umständlich ansehen, aber für mich ist das in all den Jahren so "normal" geworden, dass ich nicht mehr darüber nachdenke.
Koda ist mir zu starr und ich muss hinterher mehr nacharbeiten (die Variablennamen sind so nichtssagend und ich brauche oft Arrays), als wenn ich das gleich nach meiner Methode mache.Koda ist für Einsteiger ein gutes Hilfsprogramm, um zu sehen, welche Control-Elemente zur Verfügung stehen und wie man sie am besten anordnet.
Aber für eigene/größere Projekte kann ich es nicht empfehlen. -
Naja, ich wollte damit schon Oscars Original "ehren", die Ähnlich der Programm, auch optisch, ist ja nun frappierend. Weshalb ich ja auch gleich in der ersten Zeile auf das Original verweise.
Eine kleine Testsuche bei Tante Google ergab das es einige andere Produkte und Programme mit gleichen Namen gibt. Grenzt man die Suche ein so erscheint Oscar zuerst.
Soll sich Oscar zu äußern.Ich denke, Du hast da schon etwas Eigenes geschaffen (übrigens: Glückwunsch und gut gemacht!), deswegen ist es durchaus angebracht, dem Kind einen eigenen Namen zu geben.
Nur weil Du einen Teil meines Codes benutzt, musst Du Dich nicht dahingehend verpflichtet fühlen. Ich habe jetzt auch bei Heise-Download gesehen, dass es noch ein FotoSort gibt.
Es wird also wohl Zeit für einen anderen Namen.
-
Liefert 256 = UTF-8 ohne BOM auch wenn man in die Datei schreibt.
Besitzt Du seine Datei?
Er hat doch seine Datei zum lesen geöffnet, deswegen gehe ich davon aus, dass da auch etwas drin steht.
Und deswegen mein Hinweis, vorher erstmal schauen was FileGetEncoding sagt. -
Was sagt denn FileGetEncoding?
-
Ich hoffe, ich gehe Dir mit meiner 120% DPI Nummer nicht auf die Nerven
Ah! Ich hab's wieder vergessen!
Dabei wollte ich doch dran denken. Danke, für den Hinweis!kannst du "_GetWeekNumber" nicht durch die offizielle Funktion _GetWeekNumber bzw "_IsLeapyear" durch "_DateIsLeapYear" ersetzen?
Eigentlich ist das peinlich, aber ich wusste gar nicht, dass es eine "offizielle" Version von GetWeekNumber gibt.
Deswegen hatte ich ja meine Version geschrieben. Ich hatte immer unter den _Date-Befehlen gesucht.
Irgendwie passt das mit der Benennung ("_WeekNumberISO") der Funktion nicht so ganz.
Trotzdem danke für den Hinweis!Es gibt jetzt eine korrigierte Version (Post#1).
-
Bei dieser UDF handelt es sich um einen Kalender, den man auf der eigenen GUI anzeigen lassen kann. Die Abmessungen des Kalenders sind (Breite x Hoehe = 460 x 380 px).
Man kann auch mehrere Kalender auf der GUI erstellen lassen. Im Beispiel-Script habe ich zwei Kalender benutzt.
Die Samstage und Sonntage haben standardmäßig bereits eine andere Farbe als die anderen Wochentage.
Außerdem kann man einzelne Tage im Kalender markieren (fett, kursiv, unterstrichen, durchgestrichen, Vorder- und Hintergrundfarbe aendern), um Geburtstage, Urlaub, Feiertage, etc. besonders darzustellen.Screenshot:
GuiCtrlCalendar_Screenshot.pngUpdate 11.07.2017:
- Es wird nun die DPI-Einstellung von Windows berücksichtigt. Danke Musashi!
- Meine andere UDF "GetWeekNumber" wird gar nicht benötigt. Es gibt ja "_WeekNumberISO" in der Date-UDF.
-
Wenn Du die Laufschrift über den ganzen Bildschirm haben willst, dann $iMarqueeLeft auf Null setzen. Das setzt auch den rechten Rand auf Null.
Und wenn Du $iMarqueeHeight größer machst, dann kannst Du auch den Zeichensatz noch größer machen:Spoiler anzeigen
AutoIt
Alles anzeigen#include <GDIPlus.au3> #include <GDIPlusConstants.au3> #include <GUIConstantsEx.au3> #include <Math.au3> #include <WinAPI.au3> #include <WindowsConstants.au3> Opt('GUIOnEventMode', 1) ; Ein Array mit den Scroll-Texten erstellen (kann beliebig erweitert werden, das Ende wird per UBound abgefragt) Global $aNewsText[] = ['(1/2) Dieser Text hier wird über den Bildschirm gescrollt.', '(2/2) Und dieser Text folgt als nächstes'] Global Const $iMainWidth = 1920, $iMainHeight = 210 ; die Groesse des Fensters Global Const $iMarqueeWidth = 4000 ; Die Breite, die hier angegeben wird, muss groesser als die Fensterbreite sein, weil der Scrolltext komplett hineinpassen muss Global Const $iMarqueeHeight = 90 ; Die Hoehe der Laufschrift Global Const $iMarqueeLeft = 0, $iMarqueeTop = 60 ; die Position, an der die Laufschrift auf dem Fenster angezeigt werden soll _GDIPlus_Startup() Global $hMarqueeGui = GUICreate('Laufschrift-Beispiel', $iMainWidth, $iMainHeight, -1, -1, $WS_POPUPWINDOW) GUISetBkColor(0x0AFF0A) ; Hintergrundfarbe des Fensters (RGB) GUISetOnEvent($GUI_EVENT_CLOSE, '_CloseMarqueeGui') Global $hDC_Marquee = _WinAPI_GetDC($hMarqueeGui) Global $hDC_MarqueeBB = _WinAPI_CreateCompatibleDC($hDC_Marquee) Global $hBMP_Marquee = _WinAPI_CreateCompatibleBitmap($hDC_Marquee, $iMarqueeWidth, $iMarqueeHeight) Global $hBMP_Old = _WinAPI_SelectObject($hDC_MarqueeBB, $hBMP_Marquee) Global $hGC_Marquee = _GDIPlus_GraphicsCreateFromHDC($hDC_MarqueeBB) _GDIPlus_GraphicsClear($hGC_Marquee, 0xFF0AFF0A) ; Hintergrundfarbe der Laufschrift (ARGB) _GDIPlus_GraphicsSetSmoothingMode($hGC_Marquee, $GDIP_SMOOTHINGMODE_HIGHQUALITY) _GDIPlus_GraphicsSetPixelOffsetMode($hGC_Marquee, $GDIP_PIXELOFFSETMODE_HIGHQUALITY) _GDIPlus_GraphicsSetTextRenderingHint($hGC_Marquee, 5) GUISetState(@SW_SHOW, $hMarqueeGui) _WinAPI_BitBlt($hDC_Marquee, $iMarqueeLeft, $iMarqueeTop, $iMainWidth - $iMarqueeLeft * 2, $iMarqueeHeight, $hDC_MarqueeBB, 0, 0, $SRCCOPY) Global $iMarqueeX = $iMainWidth - $iMarqueeLeft, $iNewsCount = 0 Global $iTextWidth = _SetMarqueeText($aNewsText[$iNewsCount]) While Sleep(10) _MarqueeScroll() WEnd Func _CloseMarqueeGui() _WinAPI_SelectObject($hDC_MarqueeBB, $hBMP_Old) _WinAPI_DeleteObject($hBMP_Marquee) _WinAPI_DeleteDC($hDC_MarqueeBB) _WinAPI_ReleaseDC($hMarqueeGui, $hDC_Marquee) _GDIPlus_GraphicsDispose($hGC_Marquee) _GDIPlus_Shutdown() GUIDelete($hMarqueeGui) Exit EndFunc ;==>_CloseMarqueeGui Func _MarqueeScroll() _WinAPI_BitBlt($hDC_Marquee, ($iMarqueeX > $iMarqueeLeft ? $iMarqueeX : $iMarqueeLeft), $iMarqueeTop, $iMainWidth - $iMarqueeLeft - ($iMarqueeX > $iMarqueeLeft ? $iMarqueeX : $iMarqueeLeft), $iMarqueeHeight, $hDC_MarqueeBB, ($iMarqueeX > $iMarqueeLeft ? 0 : $iMarqueeLeft - $iMarqueeX), 0, $SRCCOPY) $iMarqueeX -= 1 If $iMarqueeX < -$iTextWidth Then $iMarqueeX = $iMainWidth $iNewsCount += 1 If $iNewsCount = UBound($aNewsText) Then $iNewsCount = 0 $iTextWidth = _SetMarqueeText($aNewsText[$iNewsCount]) EndIf EndFunc ;==>_MarqueeScroll Func _SetMarqueeText($sText, $iTextColor = 0x000000, $iBkColor = 0x0AFF0A) Local $hBrush = _GDIPlus_BrushCreateSolid(BitOR(0xFF000000, $iTextColor)) Local $hFormat = _GDIPlus_StringFormatCreate() Local $hFamily = _GDIPlus_FontFamilyCreate('Times New Roman') Local $hFont = _GDIPlus_FontCreate($hFamily, 48, 3) Local $tLayout = _GDIPlus_RectFCreate(0, 6, $iMarqueeWidth, $iMarqueeHeight - 10) Local $aInfo = _GDIPlus_GraphicsMeasureString($hGC_Marquee, $sText, $hFont, $tLayout, $hFormat) Local $iTextWidth = Ceiling(DllStructGetData($aInfo[0], 'Width')) Local $hPen = _GDIPlus_PenCreate(0xFF000000, 8) _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDASHDOT) _GDIPlus_PenSetDashCap($hPen, $GDIP_DASHCAPTRIANGLE) _GDIPlus_GraphicsClear($hGC_Marquee, BitOR(0xFF000000, $iBkColor)) _GDIPlus_GraphicsDrawLine($hGC_Marquee, 0, 0, $iTextWidth, 0, $hPen) _GDIPlus_GraphicsDrawLine($hGC_Marquee, 0, $iMarqueeHeight - 0, $iTextWidth, $iMarqueeHeight - 0, $hPen) _GDIPlus_GraphicsDrawStringEx($hGC_Marquee, $sText, $hFont, $aInfo[0], $hFormat, $hBrush) _GDIPlus_PenDispose($hPen) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_BrushDispose($hBrush) Return $iTextWidth EndFunc ;==>_SetMarqueeTextAch, und ARGB ist eigentlich das gleiche wie RGB, nur dass davor noch der Alphawert steht.
Bei den Hexwerten von RGB stehen jeweils 2 Stellen für Rot, 2 für Grün und 2 für Blau. Bei ARGB brauchst Du vorne nur 2 Stellen für den Alphawert vorsetzen.