删除 Pascal 字符串中的短词

Delete short words in a Pascal string

我需要删除以点结尾的字符串中的短词(短于三个符号)。然后显示没有这些词的字符串。

所以我们需要一个来自用户的字符串作为输入,如下所示:"This is a simple string a man types." 在这个字符串中,程序应该删除每个短于三个符号的单词。在我们的字符串中,这些是:"is, a, a"。所以输出应该是 "This simple string man types."

这是我的编程课程的 Pascal/Delphi 任务。

几天来我一直在思考这个简单的问题,显然 运行 不知道如何解决它并寻求您的帮助。我为主要部分尝试了不同的循环,主要是在空格之间找到少于三个符号的序列。我尝试调试了一段时间,但没有结果。

我使用 Lazarus 1.6.2、FPC 3.0 和 Mac OS X v10.11 (El Capitan)。我的代码如下:

 VAR
   UserString: string;
   i, n: byte;    // Counters for the symbols in the string. 'i' counts every symbol.
   again: boolean;   // In case we need to repeat the program again
   UserAnswerRepeat: char;
   label repeat_again;

 BEGIN
   again:=false;
 repeat_again:                 // Label to repeat the program
   Writeln('Enter your string (ended by a dot):');
   Readln(UserString);

   // MAIN LOOP:
   n:=1;              // 'n' counts symbols in the words
   for i:=1 to length(UserString) do
   begin
     while (UserString[i] <> ' ') do inc(n); // Here I have Range Check Error. Don't know how to get rid of it.
     if (UserString[n] <> ' ') and (n<3) then
     begin
       delete(UserString, i-n, n);
       n:=1
     end;
   end;

   Writeln('The result is: ', UserString);

   Writeln('Do you want to repeat the program? (Y/N)');
   Readln(UserAnswerRepeat);
   if (UserAnswerRepeat = 'Y') or (UserAnswerRepeat = 'y')  then
     again:=true;
   if (again = true) then
     goto repeat_again;
 END.

另一个小问题是:如何让您的控制台应用程序在成功 运行 后重复?这里我使用了 labels 和 goto。也许还有另一种好方法可以重做?

A for 控制变量的循环开始和结束值仅计算一次。您将结束值设置为字符串的长度。但是,在循环期间,您从字符串中删除了部分,因此结束值超过了字符串的末尾。尝试使用 while 循环或 repeat .. until 循环。

错误的实际原因在行

  while (UserString[i] <> ' ') do inc(n);

循环会持续多久?什么结束了循环?

您还需要重新考虑如何使用 n.

计算字符

在这种情况下寻找单词分隔符。在你的例子中是 'space'。另外,计算点之前的最后一个单词,因为它后面没有 'space'.

编写主循环的一种方法是:

var
  LastPos, I: Integer;
  Tmp, UserString: String;
begin
  LastPos := 1;
  Tmp := '';
  for I := 1 to Length(UserString) do
  begin
    if (UserString[I] = ' ') or (I = Length(UserString)) then
    begin
      if (I - LastPos >= 3) then Tmp := Tmp + Copy(UserString, LastPos, I - LastPos + 1);
        LastPos := I + 1;
    end;
  end;
  UserString: = Tmp; 
end;

再次感谢大家指出了正确的方向。我终于想出了我最初想要的解决方案,这样程序实际上删除了短的(少于 3 个符号)单词。这是我得到的:

VAR
UserString: string; //должна быть строка на 40 символов и точку в конце
i, n: byte;

BEGIN
Writeln('Enter the string:');
Readln(UserString);

i:=0;
n:=1;    

repeat       //MAIN LOOP:

  inc(i);
  if (UserString[i] = ' ') or (UserString[i] = '.') then

     begin
        if (i-n<3)then
        begin
        delete(UserString, n, i-n+1);
        i:=n-1;
        end;
        n:=i+1
     end

until (UserString[i] = '.') or (i>length(UserString));

Writeln('Result String: ', UserString);
END.

欢迎提出任何建议!还有一个关于让程序在控制台模式下重复的悬而未决的问题。标签是最好的方法吗(请参阅问题部分的第一个代码)?

另一种方法:

uses classes;

var v : TStringlist;
    i : integer;
begin
 v :=TStringlist.create;
 v.strictdelimiter:=true;
 v.delimiter:=' ';
 v.delimitedtext:='This is a simple string a man types';
 for i:=v.count-1 downto 0 do
    if length(v[i])<3 then
       v.delete(i);
 writeln(v.delimitedtext);
 v.free;
end.