ADD: Find text in files by regular expression, work with any single byte encoding

This commit is contained in:
Alexander Koblov 2017-08-22 19:01:34 +00:00
commit 61769c29d3
4 changed files with 104 additions and 13 deletions

View file

@ -705,11 +705,8 @@ end;
{ TfrmFindDlg.cmbEncodingSelect }
procedure TfrmFindDlg.cmbEncodingSelect(Sender: TObject);
var
AEncoding: string;
begin
AEncoding := NormalizeEncoding(cmbEncoding.Text);
cbTextRegExp.Enabled := (AEncoding = EncodingAnsi);
cbTextRegExp.Enabled := cbFindText.Checked and SingleByteEncoding(cmbEncoding.Text);
if not cbTextRegExp.Enabled then cbTextRegExp.Checked := False;
end;
@ -774,6 +771,7 @@ begin
EnableControl(cbTextRegExp, cbFindText.Checked);
lblEncoding.Enabled := cbFindText.Checked;
cbReplaceText.Checked := False;
cmbEncodingSelect(nil);
if not FUpdating and cmbFindText.Enabled and cmbFindText.CanFocus and (Sender = cbFindText) then
begin
@ -847,6 +845,7 @@ begin
cbCaseSens.Checked := False;
cbNotContainingText.Checked := False;
cmbEncoding.ItemIndex := 0;
cmbEncodingSelect(nil);
// plugins
cmbPlugin.Text := '';

View file

@ -425,6 +425,7 @@ end;
function SingleByteEncoding(TextEncoding: String): Boolean;
begin
TextEncoding := NormalizeEncoding(TextEncoding);
if TextEncoding = EncodingDefault then TextEncoding := GetDefaultTextEncoding;
Result := (TextEncoding <> EncodingUTF8) and (TextEncoding <> EncodingUTF8BOM) and
(TextEncoding <> EncodingUCS2LE) and (TextEncoding <> EncodingUCS2BE);
end;

View file

@ -27,7 +27,7 @@ unit uFindThread;
interface
uses
Classes, SysUtils, uFindFiles, uFindEx, uFindByrMr, uMasks;
Classes, SysUtils, uFindFiles, uFindEx, uFindByrMr, uMasks, uRegExpr;
type
@ -50,6 +50,7 @@ type
FFilesMasks: TMaskList;
FExcludeFiles: TMaskList;
FExcludeDirectories: TMaskList;
FRegExpr: TRegExprEx;
FTimeSearchStart:TTime;
FTimeSearchEnd:TTime;
@ -62,6 +63,7 @@ type
function CheckFile(const Folder : String; const sr : TSearchRecEx) : Boolean;
function CheckDirectory(const CurrentDir, FolderName : String) : Boolean;
function FindInFile(const sFileName: String;sData: String; bCase, bRegExp: Boolean): Boolean;
procedure FileReplaceString(const FileName, SearchString, ReplaceString: string; bCase, bRegExp: Boolean);
protected
procedure Execute; override;
@ -107,14 +109,10 @@ begin
if IsFindText then
begin
TextEncoding := NormalizeEncoding(TextEncoding);
if TextRegExp then FRegExpr := TRegExprEx.Create(TextEncoding);
FindText := ConvertEncoding(FindText, EncodingUTF8, TextEncoding);
ReplaceText := ConvertEncoding(ReplaceText, EncodingUTF8, TextEncoding);
if TextEncoding = EncodingDefault then begin
if not SingleByteEncoding(GetDefaultTextEncoding) then
TextEncoding := GetDefaultTextEncoding;
end;
// Determine search type
if SingleByteEncoding(TextEncoding) then
begin
@ -155,6 +153,7 @@ end;
destructor TFindThread.Destroy;
begin
// FItems.Add('End');
FreeAndNil(FRegExpr);
FreeAndNil(FFilesMasks);
FreeAndNil(FExcludeFiles);
FreeThenNil(FLinkTargets);
@ -275,7 +274,7 @@ begin
finally
fs.Free;
end;
Exit(ExecRegExpr(sData, S));
Exit(FRegExpr.ExecRegExpr(sData, S));
end;
if gUseMmapInSearch then
@ -366,7 +365,7 @@ begin
end;
end;
procedure FileReplaceString(const FileName, SearchString, ReplaceString: string; bCase, bRegExp: Boolean);
procedure TFindThread.FileReplaceString(const FileName, SearchString, ReplaceString: string; bCase, bRegExp: Boolean);
var
S: String;
fs: TFileStreamEx;
@ -386,7 +385,7 @@ begin
end;
if bRegExp then
S := ReplaceRegExpr(SearchString, S, replaceString, True)
S := FRegExpr.ReplaceRegExpr(SearchString, S, replaceString, True)
else
begin
Include(Flags, rfReplaceAll);

92
src/uregexpr.pas Normal file
View file

@ -0,0 +1,92 @@
unit uRegExpr;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, RegExpr;
type
TRecodeTable = array[Byte] of Byte;
type
{ TRegExprEx }
TRegExprEx = class(TRegExpr)
private
FLowerCase,
FUpperCase: TRecodeTable;
protected
function RegExprInvertCaseFunction(const Ch: REChar): REChar;
public
constructor Create(const AEncoding: RegExprString); reintroduce;
public
function ExecRegExpr(const ARegExpr, AInputStr: RegExprString): Boolean;
function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString;
AUseSubstitution: Boolean = False): RegExprString;
end;
implementation
uses
LazUTF8, LConvEncoding, uConvEncoding;
function InitRecodeTable(Encoding: String; ALowerCase: Boolean): TRecodeTable;
var
I: Byte;
C: String;
begin
if ALowerCase then
begin
for I:= 0 to 255 do
begin
C:= ConvertEncoding(Chr(I), Encoding, EncodingUTF8);
C:= UTF8LowerCase(C);
C:= ConvertEncoding(C, EncodingUTF8, Encoding);
if Length(C) > 0 then Result[I]:= Ord(C[1]);
end;
end
else begin
for I:= 0 to 255 do
begin
C:= ConvertEncoding(Chr(I), Encoding, EncodingUTF8);
C:= UTF8UpperCase(C);
C:= ConvertEncoding(C, EncodingUTF8, Encoding);
if Length(C) > 0 then Result[I]:= Ord(C[1]);
end;
end;
end;
{ TRegExprEx }
function TRegExprEx.RegExprInvertCaseFunction(const Ch: REChar): REChar;
begin
Result:= Chr(FUpperCase[Ord(Ch)]);
if Result = Ch then Result:= Chr(FLowerCase[Ord(Ch)]);
end;
constructor TRegExprEx.Create(const AEncoding: RegExprString);
begin
inherited Create;
InvertCase:= @RegExprInvertCaseFunction;
FLowerCase:= InitRecodeTable(AEncoding, True);
FUpperCase:= InitRecodeTable(AEncoding, False);
end;
function TRegExprEx.ExecRegExpr(const ARegExpr, AInputStr: RegExprString): Boolean;
begin
Self.Expression:= ARegExpr;
Result:= Self.Exec(AInputStr);
end;
function TRegExprEx.ReplaceRegExpr(const ARegExpr, AInputStr,
AReplaceStr: RegExprString; AUseSubstitution: Boolean): RegExprString;
begin
Self.Expression:= ARegExpr;
Result:= Self.Replace(AInputStr, AReplaceStr, AUseSubstitution);
end;
end.