【问题标题】:Delphi load name/value pair from text fileDelphi 从文本文件中加载名称/值对
【发布时间】:2015-07-17 21:58:00
【问题描述】:

想要将名称值对加载到 TStringList 中。

有一个包含数据的文本文件:

a=ant
a=animal
b=bob
d=darn

加载函数:

LoadData(argPath: string): TStringList;
var
  data: TStringList;
begin
  data := TStringList.Create(true);
  data.Delimiter := '=';
  try
    data.LoadFromFile(argPath);
  except on E : Exception do
  begin
    Application.MessageBox(PWideChar(E.Message), 
       'Unable to Load Data', MB_OK or MB_ICONERROR);
    Application.Terminate;
  end;
  end;
  Result := data;
end;

目前的结果是:

a=ant
a=animal
b=bob
d=darn

希望结果的字符串是:

ant
animal
bob
darn

Result 的 TObjects 是

a
a
b
d

之后我希望能够在 TComboBox 中显示它。

【问题讨论】:

  • 名字总是单字符吗?因为如果是这样,您可以简单地将其序数值存储为对象(在手动解析之后)。 [没有考虑到这种特殊要求的怪异...] P.S. Delimiter 属性与名称值对无关(您可能一直在寻找 NameValueSeparator)。
  • ...默认已经是=了。
  • 使用 LoadFromFile,Result 的字符串将是 name=value 对,Result.Object[x] 将全部为零。字符串值 a、a、b、d 不是对象,它们是字符串,你不说它们应该是什么类型的对象。因此,目前尚不清楚您要在这里完成什么。此外,当您说“我希望能够在 TComboBox 中显示这个”时,不清楚“这个”指的是什么;名称部分、值部分或完整的名称=值字符串?
  • 顺便说一句,您抛出的异常很奇怪。出现异常的唯一原因是文件不存在或内存不足。一个更好的方法是测试FileExists(argPath) 并抛出一个错误或异常,说明为什么如果不是。不要等待 LoadFromFile 失败然后抛出无意义的错误消息。虽然这可能只是为了简单的测试,但您通常不希望在方法中的异常中终止应用程序。让外部范围内的异常处理程序处理它(如果存在)。如果没有,那么应用程序将自行终止。
  • 你已经陈述了你拥有什么以及你想要实现什么,但你还没有提出问题。你有什么困难?您已经了解分隔符、字符串和对象;是什么阻止你采取下一步行动并做你想做的事? (顺便说一句,将字符串存储在Objects 属性中确实不是一个好主意。如果您想要名称和值的列表,请考虑使用TDictionary。)

标签: delphi delphi-xe4 tstringlist


【解决方案1】:

您必须使用 TStringList 中的内置函数。为了便于阅读/理解,我将其分解为变量,但可以压缩:

var
  X: Integer;
  Name, Value: String;
begin
  for X:= 0 to MyList.Count - 1 do begin
    Name:= MyList.Names[X];
    Value:= MyList.ValueFromIndex[X];
    MyCombo.Items.Add(Value);
  end;
end;

有了这个,我相信你可以弄清楚其余的(因为我不确定你所说的结果字符串和对象到底是什么意思)。

【讨论】:

  • 使用Value := MyList.ValueFromIndex[X];而不是Value := MyList.Values[Name];会更安全、更高效。然后您不必担心重复名称,O.O 的示例清楚地表明确实存在重复名称。 ValueFromIndex[] 属性从 Delphi 7 开始就存在了。
  • @Remy 我正在研究 OP 打算如何使用该名称。但是,是的,这将有助于解决重复问题。实际上,直到您说了什么,我才注意到重复项。我自然而然地跳过了中间的两个字母,直接阅读a..d。更新了答案。
  • @JerryDodge - 基本上我希望能够选择“动物”作为组合框的文本,但我希望值为“a”。所以一个文本属性和一个值属性
  • 我已经按照您的要求回答了您的问题。如果您还有其他需要帮助的问题,请随时提出新问题。您似乎已经成为这里的成员足够长的时间了,知道规则是如何运作的。
【解决方案2】:

最好将字符串列表作为参数传递,以简化生命周期管理。最好让函数引发异常并在以后处理它们。这允许更大的灵活性和重用的可能性。像这样:

procedure LoadValues(const FileName: string: Values: TStringList);
var
  i: Integer;
begin
  Values.LoadFromFile(FileName);
  for i := 0 to Values.Count - 1 do
    if Pos(Values.NameValueSeparator, Values[i]) <> 0 then
      Values[i] := Values.ValueFromIndex[i];
end;

您不能将字符串直接存储在TStringsObjects[] 属性中,因为字符串是托管类型。您可能应该将名称存储在单独的字符串列表或其他功能更强大的数据结构中。使用Names[] 属性可以很容易地扩展上面的代码来填充两个列表而不是一个列表。

听起来您正试图将所有数据填充到可视控件中。不要那样做。将可视化控件视为显示数据而不是保存和管理数据的东西。

【讨论】:

    【解决方案3】:

    放弃尝试使用LoadFromFile 加载组合框。最终创建了两个单独的列表。

    FormCreate 处理程序中:

    LoadData(...)
    
    myComboBox.Items := displayList;
    

    加载数据

    procedure MyForm.LoadData(
        const path: string; data: TStringList);
    var index : Integer;
    begin
        data.LoadFromFile(path);
        for index := 0 to data.Count - 1 do
        begin
            displayList.Add(data.ValueFromIndex[index]);
            valueList.Add(data.Names[index]);
        end;
    end;
    

    每当您需要获取所选值时:

    valueList[myComboBox.ItemIndex]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 2010-12-08
      • 2011-06-26
      • 1970-01-01
      相关资源
      最近更新 更多