Delphi - 用户指定的字符串操作

4
我在Delphi7中遇到了问题。我的应用程序根据一组命名规则创建mpg视频文件,例如:\000_A_Title_YYYY-MM-DD_HH-mm-ss_Index.mpg。
在这个文件名中,强制执行以下规则:
1. 000是视频序列。每当用户按停止时,它会递增。
2. A(或B、C、D)指定录制摄像机 - 因此视频文件与最多四个同时播放的视频流相关联。
3. Title是一个可变长度的字符串。在我的应用程序中,它不能包含下划线。
4. YYYY-MM-DD_HH-mm-ss是视频序列开始时间(而不是单个文件)。
5. Index是基于0的排序索引,每个视频序列都会递增1。也就是说,视频文件最长为15分钟,一旦达到这个时间,就会以相同的序列号但下一个索引启动新的视频文件。使用这个,在我们可以计算出文件的实际开始时间(文件名解码时间+15 x Index)。
使用这种方法,我的应用程序可以提取视频文件开始录制的时间。现在,我们有进一步的要求来处理任意命名的视频文件。我唯一确定的事情是在文件名中会有一个YYYY-MM-DD HH-mm-ss。
如何让用户指定导入文件的文件名约定?类似于正则表达式之类的东西吗?我知道命名方案必须遵循某种模式。
因此,如果用户在文本框中输入?_(Camera)_*_YYYY-MM-DD_HH-mm-ss_(Index).mpg,我该如何获取开始时间?有更好的解决方案吗?还是我们必须处理每一个可能性?(我知道这可能不是处理这个问题的最佳方法,但是我们无法改变这个问题-新的视频文件是由另一家公司录制的)。

好的,我以前没有在Delphi中使用过正则表达式,因为我认为Delphi7不支持它。那么使用正则表达式是正确的方法吗? - Simon
1
有适用于旧版 Delphi 的正则表达式组件。我使用 TRegExpr,但还有许多其他选择。 - David Heffernan
2
另一个想法:如果你的用户是人类(相对于程序员这个亚种),我建议你不要向他们公开正则表达式! - David Heffernan
2
只是想插句话关于D7的正则表达式库。我已经使用了几年这个库,它基于PCRE正则表达式库。 - Nazar
哈哈,David。完全理解。 - Simon
3个回答

4

我不确定您是否试图将用户输入解析为组件 '?(相机)*_YYYY-MM-DD_HH-mm-ss_(索引).mpg`,但如果您只是想获取日期和时间,可以使用以下代码,日期在第1组,时间在第2组:

(\d{4}-\d{2}-\d{2})_(d{2}-\d{2}-\d{2})

否则,我不确定您想做什么。


谢谢,这帮助我找到了答案。正则表达式比我的旧方法干净多了:(\d+)_(\w+)_(\d{4})-(\d{2})-(\d{2})_(\d{2})-(\d{2})-(\d{2})_(\d+) - Simon

3

由于您聪明地不允许在标题中使用下划线“_”,因此您可以将其用作定位指示符。

在您的文件名约定示例中:

?_(Camera)_*_YYYY-MM-DD_HH-mm-ss_(Index).mpg 

您可以解析这个用户指定的字符串,以查看日期YYYY-MM-DD始终在第三个和第四个下划线之间,时间HH-mm-ss在第四个和第五个下划线之间。

然后,在遵循这种约定获取实际文件名时,找到第三个下划线并知道日期和时间跟随它变得非常简单。


1

如果您想要24/7的电话支持,那么您应该选择RegEx方式,并允许用户在TEdit中自由输入一些密码学。

如果您想要快乐的用户和一个良好的睡眠,那么就要有创意,放弃无聊的RegEx方法。通过使用愤怒的小鸟方法来创建自己的文件名解码器。

这里是一个想法:

  • 创建一些具有不同字符串操作特性的小鸟。
  • 让用户选择和排列这些小鸟。
  • 执行用户生成的字符串操作。

示例代码:

program AngryBirdFilenameDecoder;

{$APPTYPE CONSOLE}

uses
  SysUtils;

procedure PerformEatUntilDash(var aStr: String);
begin
  if Pos('-', aStr) > 0 then
    Delete(aStr, 1, Pos('-', aStr));
  WriteLn(':-{   >   ' + aStr);
end;

procedure PerformEatUntilUnderscore(var aStr: String);
begin
  if Pos('_', aStr) > 0 then
    Delete(aStr, 1, Pos('_', aStr));
  WriteLn(':-/   >   ' + aStr);
end;

function FetchDate(var aStr: String): String;
begin
  Result := Copy(aStr, 1, 10);
  Delete(aStr, 1, 10);
  WriteLn(':-)   >   ' + aStr);
end;



var
  i: Integer;
  FileName:      String;
  TempFileName:  String;
  SelectedBirds: String;
  MyDate:        String;
begin
  Write('Enter a filename to decode (eg. ''01-ThisIsAText-Img_01-Date_2011-03-08.png''): ');
  ReadLn(FileName);
  if FileName = '' then
    FileName := '01-ThisIsAText-Img_01-Date_2011-03-08.png';



  repeat
    TempFileName := FileName;
    WriteLn('Now, select some birds:');
    WriteLn('Bird No.1  :-{  ==> I''ll eat letters until I find a dash (-)');
    WriteLn('Bird No.2  :-/  ==> I''ll eat letters until I find a underscore (_)');
    WriteLn('Bird No.3  :-)  ==> I''ll remember the date before I eat it');
    WriteLn;
    Write('Chose your birds: (eg. 112123):');
    ReadLn(SelectedBirds);
    if SelectedBirds = '' then
      SelectedBirds := '112123';

    for i := 1 to Length(SelectedBirds) do
    case SelectedBirds[i] of
      '1': PerformEatUntilDash(TempFileName);
      '2': PerformEatUntilUnderscore(TempFileName);
      '3': MyDate := FetchDate(TempFileName);
    end;


    WriteLn('Bird No.3 found this date: ' + MyDate);
    WriteLn;
    WriteLn;
    Write('Check filename with some other birds? (Y/N): ');
    ReadLn(SelectedBirds);
  until (Length(SelectedBirds)=0) or (Uppercase(SelectedBirds[1])<>'Y');
end.

如果你在Delphi中使用GUI完成这个任务,当然会添加更多的鸟类和检查。并且找到一些漂亮的鸟类图标。

使用两个列表框。一个在左边显示所有可能的鸟类,另一个在右边显示所有选定的鸟类。将鸟从左边拖放到右边。重新排列(和删除)右侧列表中的鸟。

用户应该能够通过输入文件名来测试设置,并查看处理结果。在内部,您可以使用枚举器等方式存储脚本。


有趣的方法。我决定实现标准的Windows通配符和yyyy mm dd hh mm ss标识符,这些标识符在代码中被转换为正则表达式。我的原始文件名解码类似于这个,但只适用于我们的命名约定。尽管如此,这仍然很有启发性。 - Simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接