mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
ADD: Find text in files by regular expression, work with any single byte encoding
This commit is contained in:
parent
cd71826d1e
commit
61769c29d3
4 changed files with 104 additions and 13 deletions
|
|
@ -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 := '';
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
92
src/uregexpr.pas
Normal 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.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue