#1 2017-01-27 10:07

Stefan
Moderator
From: Germany, EU
Registered: 2007-10-23
Posts: 1,161

ReNamer: PascalScript Basics-Basket

Do you know you can extend ReNamer capabilities by writing (or find) an Script with Pascal syntax?

See our fine Wiki http://www.den4b.com/wiki/ReNamer

Pascal Script

    Quick guide
    Types
    Functions
    Script cookbook
    Scripts

For a full manual, see the wiki.


- - -

Learn Pascal tutorial
https://www.taoyue.com/tutorials/pascal

- - -


For an short overview and a few basic tricks that are not that obviously, I will post you my collection.

Over the years of trying, I have collected a few how-to's, examples, basics.
Many from Denis and from other forum members.

This are not whole scripts, I put them in code blocks only to prevent the formatting.
And that are not logically ordered blocks, just a quick copy and paste while trying to keep things together.

Hope that helps somebody.
(Please, do not ask here for whole scripts, create an new thread for that. Basic questions may be OK)


- - -
To add a comment for rules, add an extra PascalScipt rule and add your comments there.

You can use either of these commenting styles in PascalScipt:

{ comments }
// comments
(* comments *)

For Regex (RegEx rule) you can put (?#comment) at the beginning of the expression.

- - -

var
  bStopScript, Initialized     : Boolean;
  StringParts, RegExSubPatterns: TStringsArray;
  BaseName, Extension, pattern : WideString;
  i, x, Count, Pos: Integer;
  

Procedure Initialize;
  BEGIN
  //do something only once:
  Initialized := True;
  END.
  
  
begin
if not bStopScript then
    begin

      //trick to stop whole script (use for debugging scripts)
      if DialogYesNo('Would you like to stop whole script execution?') then
          begin
             bStopScript := True;
             Exit;
          end;

      //////////////////////////////////////////
      // Add your code here
      
      
      //do something only once:
      if not Initialized then Initialize;


      //////////////////////////////////////////
      //Show an message only once:
      If Not Initialized Then
          ShowMessage('Please');
      Initialized := true


      //////////////////////////////////////////
      //Debug MsgBox:
       WideShowMessage( 'var is: ' + #13#10 + var );
      
     //compose new file name:
      FileName := BaseName + Extension;


    end;
end.
//build-in variable to use:
FileName
FilePath
GetCurrentFileIndex 
GetCurrentMarkedFileIndex
GetTotalNumberOfFiles 
GetTotalNumberOfMarkedFiles

//set own basic variable:
BaseName  := WideExtractBaseName(FileName);
Extension := WideExtractFileExt(FileName);
Count := Count + 1;


//skip for current file if condition is true:
if <Condition> then Exit;
if Count > 25 then Exit;
if GetCurrentFileIndex > 25 then Exit;
if DialogYesNo('Would you like to skip this file?') then Exit;
// split the filename at '-' into parts:
StringParts := WideSplitString( BaseName, ' - ' );
if Length(StringParts) < 1 then Exit;
// Note: parts are numbered from 0 on: StringParts[0],StringParts[1]
for I:=0 to Length(StringParts)-1 do
begin
// access each part via StringParts[i]
if <Condition> then Break;
end;

// split the filename into parts by utilizing regular expressions:
//SubMatchesRegEx create an array of matches from expression in () parentheses:
//SubMatchesRegEx(const Input, Find: WideString;const CaseSensitive: Boolean): TStringsArray;
RegExSubPatterns:=SubMatchesRegEx(BaseName,'(.*?)\[(\d+) by (\d+)\]',false);
if Length(RegExSubPatterns) <=0 then exit;

    vBefore := SubPatterns[0]
    vDigit1 := SubPatterns[1]


    
// Get parts of the current file name (default build-in):
//  C:\folder\sub folder\file.ext
//  WideExtractFileDir(FilePath)   ==> C:\folder\sub folder
//  WideExtractFilePath(FilePath)  ==> C:\folder\sub folder\
//  WideExtractFileDrive(FilePath) ==> C:\
//  WideExtractFileName(FilePath)  ==> file.ext
//  WideExtractBaseName(FilePath)  ==> file
//  WideExtractFileExt(FilePath)   ==> ext
vExt_wo_dot := WideReplaceStr( Extension, '.', '');

// Get parts of the current file path by build-in functions:
WideExtractFileName(WideExtractFileDir(FilePath)); 	=> ParentFolder
WideExtractFileName(WideExtractFileDir(WideExtractFileDir(FilePath))); =>	GrandParent
WideExtractFileName(WideExtractFileDir(WideExtractFileDir(WideExtractFileDir(FilePath)))); =>	GreatGrand 

// Get parts of the current file path by folder array:
var - Folders: TStringsArray;
Folders := WideSplitString(FilePath, '\');
TopMostFolder          := Folders[1];
SecondTopMostFolder    := Folders[2];
GrandGrandParentFolder := Folders[Length(Folders)-3];
GrandParentFolder      := Folders[Length(Folders)-2];
ParentFolder           := Folders[Length(Folders)-1];


//get part of filename:
var -  Beginning, Ending: WideString;
Beginning := WideCopy(BaseName, 1, 2); // first two signs
Ending    := WideCopy(BaseName, Length(BaseName)-3, 3); // last three
Ending    := WideCopy(BaseName, 3, 999); // from third till end

var -  FirstChar, FirstPart, SecondPart: WideString; Pos1, Pos2:Integer;
Pos1       := WidePos( '-' , BaseName );
if Pos1 <= 0 then Exit;
Pos2 := WidePosEx('-', BaseName, Pos1 + 1);
if Pos2 <= 0 then Exit;

FirstChar := Copy(BaseName,1,1);
FirstPart := Copy(BaseName,1, Pos1);
SecondPart := Copy(BaseName,Pos1 + 1,999);
//MatchesRegEx returns full expression matches:
ReplaceRegEx(const Input, Find, Replace: WideString;const CaseSensitive, UseSubstitution ($0,$2,$3,...): Boolean): WideString;
//MatchesRegEx returns an array of full matches, which matched the entire expression, not the sub-patterns.
MatchesRegEx(const Input, Find: WideString;const CaseSensitive: Boolean): TStringsArray;

WideReplaceStr(const S, OldPattern, NewPattern: WideString): WideString; //(Case Sensitive)
WideReplaceText(const S, OldPattern, NewPattern: WideString): WideString;//(Case Non-Sensitive)

WideCompareStr(const S1, S2: WideString): Integer;//(Case Sensitive)
WideCompareText(const S1, S2: WideString): Integer;//(Case Non-Sensitive)
Returns: < 0 if S1<S2 // 0  if S1=S2 // > 0 if S1>S2
WideSameText(const S1, S2: WideString): Boolean;//(Case Non-Sensitive)


// FileName := WideReplaceStr(FileName, '-', '_');

// find two identical chars in filename and delete one of them: 
//(5. Delete double letters: "Madonna" =>"Madona")
 FileName := ReplaceRegEx(FileName, '(.)\1', '$1', False, True);

- - -

//Change Case:
WideCaseCapitalize( xxx );
WideUpperCase( xxx );
WideLowerCase( xxx );
WideCaseInvert( xxx );



Rev String
Reverse Name
Reverse String

http://www.den4b.com/forum/viewtopic.php?id=930  - 2010
PascalScript only has bare bones for executing scripts. I define/code all the functions. 
No, there is no string reversal function. For the exercise above you can simple use 
reverse loop "for..downto..do" or a while loop counting down.
-----
var
 name, eman:String;
 c: Integer;

begin
    name := 'Stefan';

   //eman := '';
   for c:=length(name) downto 1 do
       eman := eman + name[c];
  
  showmessage(eman);
end.

--------------

A correct version of the string reverse function would be:

function WideReverseStr(const S: WideString): WideString;
var
  I, Count: Integer;
begin
  Count := Length(S);
  SetLength(Result, Count);
  for I := 1 to Count do
    Result[i] := S[Count - I + 1];
end;
---------------------------------------------------------- 
type
  THelloWorld = class
    procedure Put;
  end;

procedure THelloWorld.Put;
begin
  ShowMessage('Hello, World!');
end;

var
  HelloWorld: THelloWorld;

begin
  HelloWorld := THelloWorld.Create;
  HelloWorld.Put;
  HelloWorld.Free;
end.

- - -

- - -
IntToStr( integer );
StrToInt( string );

Words := WideSplitString( BaseName, ' '   );

Some function I have found useful, and as base for own work:

//from Denis Encrypt filenames.pas
//ReplaceChar(Result, '/', '=');
procedure ReplaceChar(var Str: String; Find, Replace: Char);
var
  I: Integer;
begin
  for I:=1 to Length(Str) do
    if Str[I] = Find then
      Str[I] := Replace;
end;
----------------------------------------------------------

function IsUp(Index: Integer): Boolean;
  begin
    Result := (Index >= 1) and (Index <= Length(S));
    if Result then Result := IsUpCache[Index-1];
end;

function IsLetter(C: Char): Boolean;
begin
  Result := UpperCase(C) <> LowerCase(C);
end;

function IsSpace(Index: Integer): Boolean;
  begin
    Result := (Index >= 1) and (Index <= Length(S));
    if Result then Result := IsSpaceCache[Index-1];
end;

function IsUpperCase(C: Char): Boolean;
begin
  Result := C = UpperCase(C);
end;

function IsLowerCase(C: Char): Boolean;
begin
  Result := C = LowerCase(C);
end;

function BoolToStr(condition : boolean) : WideString;
begin
   If condition Then
        result := 'True'
     Else
        result := 'False';
end;
PressedButton: boolean;
UserInput: string;
UserInput     := 'defaultstring';
PressedButton :=  InputQuery('Title', 'Prompt', UserInput);
//if PressedButton=True then OK was pressed, if False then Cancel was pressed.
 IF (PressedButton = False) Then
    begin
      WideShowMessage('Cancel pressed');
      exit;
    end;
 IF (UserInput = '') Then
    WideShowMessage('Empty string!')
 ELSE
    FileName := UserInput + WideExtractFileExt(FileName);
if <condition> then
begin
  <Action>
end;
--------
if <condition> then
begin
  <Action-1>
end else
begin
  <Action-2>
end;
----------
if sVar1 = sVar2 then 
----------
if start_pos < Length(BaseName) then
-------
if (I > 1) then
if PosEnd > 0 then
if (Length(Exts) > 0) then
if (IncYear(bday, 1) <= filedt) then
---------
if first > second then
--------
if ((Num > 0) and (5 / Num = 1)) then
--------
if not Initialized then Initialize;
-------------
if sLine <> '' then
if (TridAnalyze <> 0) then
----------
else if WideSameText(WideLowerCase(sUserInput),'stop') then 
---------
if (not WideFileExists('TrIDLib.dll')) 
 Or (WideFileSize('TrIDLib.dll')=0)
  Or (not WideFileExists('TrIDDefs.trd')) 
   Or (WideFileSize('TrIDDefs.trd')=0) then
---------------
if (DialogYesNo('Error! not found!' + #13#10 + 'Do you want to ...?')) then
------------
if IsWideCharDigit(S[i]) then
   begin
        PosEnd := I;
        Break;
   end;
-------------------
if Number > MaxNumber then MaxNumber := Number;
--------------
if Copy(dateText, 1, 3) = 'JAN' then iMonth := 1
  else if Copy(dateText, 1, 3) = 'FEB' then iMonth := 2
  ...
  else if Copy(dateText, 1, 3) = 'DEC' then iMonth := 12
  else iMonth := -1;


-or better-
varX := Copy(dateText, 1, 3);
if varX = 'JAN' then iMonth := 1
  else if varX = 'FEB' then iMonth := 2
  ...
  else if varX = 'DEC' then iMonth := 12
------------------
Result := (PosStart > 0) and (PosEnd > 0);
  if Result then
-------------
 if PADTO > 1 then
      while Length(Value) < PADTO do
        Value := '0'+Value;
----------
for I:=x to y do
begin
  <Action>
end;
---------
for I:=Length(S) downto 1 do
for I:=0 to Length(Files)-1 do
-----------
for I := Length(FileName) downto 1 do
    begin
      if (FileName[i] = '.') then
--------------

while <condition> do
begin
  <Action>
end;
---------
repeat
  <Action>
until <condition>;
---------
FormatDateTime

sDate :=  FormatDateTime(  'yyyy-mm-dd hh.MM.ss',  FileTimeModified(FilePath) );


http://www.den4b.com/forum/viewtopic.php?id=1813


FormatDateTime() needs an DateTime object as second parameter, not just an string called DateTime.

The first parameter of FormatDateTime() is a string in single quotes without parentheses, if you not want those in the result.
(The example you have found use parentheses in the first parameter as literal text for the output only)


See help > http://www.den4b.com/wiki/ReNamer:Pasca … e_and_Time

"function FormatDateTime(const Fmt: String; D: TDateTime): String;"
That means:
function FormatDateTime( wanted format as String ; working on a Date as TDateTime object): resulting in a String object;


See help from where you can get a "TDateTime" object for the second FormatDateTime() parameter, for example:
function FileTimeModified(const FileName: WideString): TDateTime;
function Date: TDateTime;
function Time: TDateTime;
function Now: TDateTime;
function EncodeDate(Year, Month, Day: Word): TDateTime;
+++
all this functions gives you a TDateTime object.


So you can use for example:
(To make it more clear, I would name the var "DateTime" rather "dtDateTime")

BEFORE:
French.txt
AFTER:
French26-Mai-2013.txt
USE:

var
  dtDateTime  :TDateTime;
  strDateTime :String;

begin
  dtDateTime  := Date();
  strDateTime := FormatDateTime('dd-mmm-yyyy', dtDateTime);
  
    FileName := WideExtractBaseName(FileName) +
                strDateTime +
                WideExtractFileExt(FileName);
end.





Or, if you prefer the short form, you can just use the function 'Date()' inside the function 'FormatDateTime()':

begin
    FileName := WideExtractBaseName(FileName) +
                FormatDateTime(  'dd-mmm-yyyy',  Date()  ) +
                WideExtractFileExt(FileName);
end.

You could even use the function Date() without the parenthesis,
but with () it makes more clear where  'Date' comes from.

- - -

To format the output (the new filename) you can add more literal text in single quotes:

BEFORE:
French.txt
AFTER:
French (26-Mai-2013).txt
USE:

begin
    FileName := WideExtractBaseName(FileName) + 
                ' (' + FormatDateTime('dd-mmm-yyyy', Date() ) + ')' +
                WideExtractFileExt(FileName);
end.;


BEFORE:
French.txt
AFTER:
French - 26-Mai-2013.txt
USE:

begin
    FileName := WideExtractBaseName(FileName) + ' - ' +
                FormatDateTime('dd-mmm-yyyy', Date() ) +
                WideExtractFileExt(FileName);
end.


BEFORE:
French.txt
AFTER:
2013.05.26 French.txt
USE:

begin
    FileName := FormatDateTime('yyyy.mm.dd', Date() ) + ' ' +
                WideExtractBaseName(FileName) +
                WideExtractFileExt(FileName);
end.


- - -

You may see that it makes sense to use the long form
to do it step-by-step and that way making the code not that confusing ;-)

BEFORE:
French.txt
AFTER:
French (26-Mai-2013).txt
USE:

var
  dtDateTime  :TDateTime;
  strDateTime :String;

begin
  dtDateTime  := Date();
  strDateTime := FormatDateTime('dd-mmm-yyyy', dtDateTime);
  
    FileName := WideExtractBaseName(FileName) +
                ' (' + strDateTime + ')' +
                WideExtractFileExt(FileName);
end.

Last edited by Stefan (2017-02-02 11:35)


Read the  *WIKI* for HELP + MANUAL + Tips&Tricks.
If ReNamer had helped you, please *DONATE* to Denis or buy a PRO license. (Read *Lite vs Pro*)

Offline

#2 2017-01-30 21:26

RecordMan
Member
Registered: 2016-12-21
Posts: 9

Re: ReNamer: PascalScript Basics-Basket

Stefan:

I really appreciate these many examples you provided of PascalScript Code Basics. This is going to mean a giant step for my understanding of this feature in ReNamer.

RecordMan

Offline

#3 2017-01-31 09:04

Stefan
Moderator
From: Germany, EU
Registered: 2007-10-23
Posts: 1,161

Re: ReNamer: PascalScript Basics-Basket

Thank you, RecordMan.

I hope that is useful for starters.
I have learned by searching the forum for "PascalScript" or "var begin end" and learned from the best.
Also there is a collection of example scripts, selected by Denis: http://www.den4b.com/wiki/ReNamer:Scripts



 


Read the  *WIKI* for HELP + MANUAL + Tips&Tricks.
If ReNamer had helped you, please *DONATE* to Denis or buy a PRO license. (Read *Lite vs Pro*)

Offline

#4 2017-02-02 09:28

Stefan
Moderator
From: Germany, EU
Registered: 2007-10-23
Posts: 1,161

Re: ReNamer: PascalScript Basics-Basket

Try to clean-up my above first post into dedicated postings...

User Input, Ask User, MsgBox and split File name or path into parts



//Get user input:
* function        InputBox(const ACaption, APrompt, ADefault: String): String;
* function WideInputBox(const ACaption, APrompt, ADefault: WideString): WideString;

var
  vUserInput: string;
begin
//                  InputBox(const ACaption, APrompt, ADefault: string): string;
vUserInput := InputBox('My Caption', 'The Description Prompt', 'Default string');
// When user presses Cancel button, the dialog should return EMPTY string.
    //If vUserInput = '' Then Continue; // means skip this file only
    //If vUserInput = '' Then BREAK;   //  to stop the whole script.
   // (That '' is here an empty '...' string)
// your code here
   FileName :=  vUserInput + WideExtractFileExt(FileName);
end.
//Ask the user:
function        InputQuery(const ACaption, APrompt: string; var Value: string): Boolean;
function WideInputQuery(const ACaption, APrompt: WideString; var Value: WideString): Boolean;

They work exactly like InputBox/WideInputBox, 
but they will also return TRUE is user presses OK, and FALSE when user presses CANCEL.

var
    bAnswer : boolean;
    sDefault : string;

//InputQuery(const ACaption, APrompt: String; var Value: String): Boolean;
sDefault := 'defaultstring';

bAnswer := InputQuery('Question', 'Do you want?' , sDefault);
if bAnswer then ...

-or-

sDefault := 'defaultstring';
bAnswer := InputQuery('Question', 'Your new file name:' , sDefault);
IF bAnswer = False then exit
ELSE FileName = Value;
-or-

var
    PressedButton: boolean; 
    UserInput: string;

begin
   FilePath := '';
   UserInput := 'defaultstring';
   
   PressedButton :=  InputQuery('Title', 'Prompt', UserInput);
   //if PressedButton=True then OK was pressed, if False then Cancel was pressed.
     IF (PressedButton = False) Then 
        begin
          WideShowMessage('Cancel pressed');
          exit;
        end;
     IF (UserInput = '') Then 
        WideShowMessage('Empty string!')
     ELSE 
        FileName := UserInput + WideExtractFileExt(FileName);
end.
-or more simple-

In above example you can even drop the PressedButton variable
cause IF-ELSE clause can simply take the value returned by InputQuery:

   IF not InputQuery('Title', 'Prompt', UserInput) Then exit
   ELSE FileName := UserInput + WideExtractFileExt(FileName);

Generally they say that it's better not to compare booleans to true/false, but to use syntax:
If PressedButton then ...                     (which is an equivalent of    If (PressedButton = true) then ...)
If not PressedButton then ...               (which is an equivalent of    If (PressedButton = false) then ...)
bAnswer := WideDialogYesNo('Do you want?');
if bAnswer then ...



// MsgBox
// Show an MessageBox to show all possibles:

var
    newPath, oldFileName, oldBaseName, oldFileExt, oldPath, output: WideString;
    Folders: TStringsArray;
    ParentFolder,  GrandParentFolder, GrandGrandParentFolder, TopMostFolder, SecondTopMostFolder: WideString;

begin
    ////build-in variable to use:
      //FilePath (C:\folder\sub folder\file.ext)
      //FileName (file.ext)

    // Get parts of the current file name:
    oldFileName := WideExtractFileName(FileName); 
    oldBaseName := WideExtractBaseName(FileName);
    oldFileExt  := WideExtractFileExt(FileName);
    //FileExt_no_dot := WideReplaceStr( oldFileExt, '.', '');
    oldPath     := WideExtractFileDir(FilePath);

    ////Get parts of the current file path by folder array:
    Folders                := WideSplitString(FilePath, '\');
    TopMostFolder          := Folders[1];
    SecondTopMostFolder    := Folders[2];
    GrandGrandParentFolder := Folders[Length(Folders)-3];
    GrandParentFolder      := Folders[Length(Folders)-2];
    ParentFolder           := Folders[Length(Folders)-1];

    output :=          'Default vars'                + #13#10;
    output := output + 'FilePath: '       + FilePath + #13#10;
    output := output + 'FileName: '       + FileName + #13#10 + #13#10;
    output := output + 'Extracted parts'             + #13#10;
    output := output + 'WideExtractFileDrive >>> '+ WideExtractFileDrive(FilePath) + #13#10;
    output := output + 'WideExtractFileDir >>> '  + WideExtractFileDir(FilePath) + #13#10;
    output := output + 'WideExtractFilePath >>> ' + WideExtractFilePath(FilePath) + #13#10;
    output := output + 'WideExtractFileName >>> ' + WideExtractFileName(FilePath) + #13#10;
    output := output + 'WideExtractBaseName >>> ' +  WideExtractBaseName(FilePath) + #13#10;
    output := output + 'WideExtractFileExt >>> '  + WideExtractFileExt(FilePath) + #13#10 + #13#10;
    output := output + 'TopMost Folder >>> ' + TopMostFolder  + #13#10;
    output := output + 'SecondTopMost >>>> ' + SecondTopMostFolder  + #13#10;
    output := output + 'GrandGrandParent > ' + GrandGrandParentFolder  + #13#10;
    output := output + 'GrandParent >>>>>> ' + GrandParentFolder  + #13#10;
    output := output + 'Parent >>>>>>>>>>> ' + ParentFolder  + #13#10 + #13#10;
    
    WideShowMessage ( output );

//  FilePath > C:\folder\sub folder\file.ext
//  FileName > file.ext
//  WideExtractFilePath => C:\folder\sub folder\
//  WideExtractFileDir ==> C:\folder\sub folder
//  WideExtractFileDrive => C:\
//  WideExtractFileName ==> file.ext
//  WideExtractBaseName ==> file
//  WideExtractFileExt ===> ext

// Get parts of the current file path by build-in functions:
WideExtractFileName(WideExtractFileDir(FilePath));     => ParentFolder
WideExtractFileName(WideExtractFileDir(WideExtractFileDir(FilePath))); =>    GrandParent
WideExtractFileName(WideExtractFileDir(WideExtractFileDir(WideExtractFileDir(FilePath)))); =>    GreatGrand


//get part of filename:
//Example:    "The Beatles - Help him.nb4"

var
    Beginning, Ending: WideString;
begin
    Beginning := WideCopy(BaseName, 1, 4); // first four signs: 'The '
    Ending     := WideCopy(BaseName, Length(BaseName)-3, 3); // last three: 'him'
    Ending     := WideCopy(BaseName, 4, 999); // from fourth till end: 'Beatles - Help him'

-or-

//"The Beatles - Help him.nb4"
var
    FirstChar, FirstPart, SecondPart: WideString;
    Pos1, Pos2:Integer;
begin
    Pos1 := WidePos( '-' , BaseName ); //13
    if Pos1 <= 0 then Exit;
   
    Pos2 := WidePosEx('-', BaseName, Pos1 + 1); // nul, not found
    if Pos2 <= 0 then Exit;

    FirstChar  := Copy(BaseName,1,1); // 'T'
    FirstPart  := Copy(BaseName,1, Pos1); // 'The Beatles '
    SecondPart := Copy(BaseName,Pos1 + 1,999); // '- Help him'



//Debug MsgBox:
       WideShowMessage( 'My var is: ' + #13#10 + varFirstChar );



 

Last edited by Stefan (2017-02-02 09:40)


Read the  *WIKI* for HELP + MANUAL + Tips&Tricks.
If ReNamer had helped you, please *DONATE* to Denis or buy a PRO license. (Read *Lite vs Pro*)

Offline

Board footer

Powered by FluxBB