有些字符计数两次
Some characters count twice
现在我正试图在文本中找到最长的句子并打印出字符数,包括空格和类似的东西。问题是当我遇到像“š”或“á”这样的字符时,它会将它们计数两次。在那些情况下,我尝试减去一个,但这似乎也不起作用,因为它也将它们减去两次。知道我该如何解决吗?这是计数器的代码。
for i:=1 to length(text) do
case text[i] of
'.','!','?': begin
if len>p2 then p2:=len;
len:=0
end;
else inc(len);
end;
p2 是最长句子的计数器,len 是当前句子。
这对我来说适用于 ANSI 字符,包括带有变音符号的字符。由于您没有提到任何特定的字符集,并且您的问题被简单地标记为 pascal,它应该也适用于您。如果您正在处理其他字符集,那么您需要指出您正在使用哪个特定的 Pascal 编译器,因为对多字节字符的支持在各种 Pascal 方言之间有所不同。
function LongestSentenceCharCount(const Text: string): Integer;
var
Len: Integer;
LongLen: Integer;
i, CurrLen: Integer;
begin
Len := Length(Text);
CurrLen := 0;
LongLen := 0;
for I := 1 to Len do
begin
if Text[i] in ['.', '!', '?'] then
begin
if CurrLen > LongLen then
LongLen := CurrLen;
CurrLen := 0;
end
else
Inc(CurrLen);
end;
Result := LongLen;
end;
处理UTF-8、Unicode等多字节字符集-
根据 Seppy Bloom(当时是 Embarcadero RTL/VCL 的团队负责人)捐赠给 Cary Jensen 的白皮书 (PDF) Delphi Unicode Migration for Mere Mortals: Stories and Advice from the Front Lines 的一些代码,您可以使用一些自 Vista 及更高版本以来,Windows 中提供了规范化功能。我已经调整了上面的函数以使用来自 Seppy(包含在下面)的代码,以及一个示例应用程序来演示如何使用它。该代码是在 Delphi 10.1 Berlin 中开发、编译和测试的,因此如果您使用不同的编译器,则必须对其进行调整,如果您不是 运行 在 Windows Vista 或更高版本下。
program Project1;
{$APPTYPE CONSOLE}
uses
System.SysUtils, WinAPI.Windows;
const
NormalizationOther = 0;
NormalizationC = 1;
NormalizationD = 2;
NormalizationKC = 5;
NormalizationKD = 6;
function IsNormalizedString(NormForm: Integer; lpString: LPCWSTR;
cwLength: Integer): BOOL; stdcall; external 'Normaliz.dll';
function NormalizeString(NormForm: Integer; lpSrcString: LPCWSTR;
cwSrcLength: Integer; lpDstString: LPWSTR;
cwDstLength: Integer): Integer; stdcall; external 'Normaliz.dll';
function NormalizedStringLength(const Str: string): Integer;
var
Buf: string;
begin
if not IsNormalizedString(NormalizationC, PChar(Str), -1) then
begin
SetLength(Buf, NormalizeString(NormalizationC, PChar(Str),
Length(Str), nil, 0));
Result := NormalizeString(NormalizationC, PChar(Str),
Length(Str), PChar(Buf), Length(Buf));
end
else
Result := Length(Str);
end;
function LongestSentenceLen(const Text: string): Integer;
var
Len: Integer;
i, CurrLen: Integer;
begin
Len := Length(Text);
CurrLen := 0;
Result := 0;
for i := 1 to Len do
begin
// Replaces 'if Text[i] in ['.', '!', '?']', which will work
// but generates a compiler warning.
if CharInSet(Text[i], ['.', '!', '?']) then
begin
if CurrLen > Result then
Result := CurrLen;
CurrLen := 0;
end
else
Inc(CurrLen, NormalizedStringLength(Text[i]));
end;
end;
var
Test: string;
begin
Test := 'Ahoj, jak se máš? Hello World.';
WriteLn(Test);
WriteLn(Format('Longest: %d', [LongestSentenceLen(Test)]));
ReadLn;
end.
上面的输出是
Ahoj, jak se más? Hello World.
Longest: 16
最近我只在我提到的在线编译器中处理这个问题。我在其他任何地方都试过(免费的 Pascal 和 Turbo Pascal)它工作得很好。
谢谢你的帮助,我认为不同的编译器不会有什么不同。
您没有说明输入文本的表示方式,但您看到的症状与 UTF-8 输入一致。
ASCII 是一个 7 位字符集,不包含任何重音字母。您的变量 text
大概是一个字符数组。对于像 Ahoj, jak se mas?
这样的字符串,每个字符在数组中占据一个位置。对于像 Ahoj, jak se máš?
这样的字符串,'á'
和 'š'
字符在 ASCII 范围之外,每个字符表示为 2 个字节,因此在数组中有 2 个槽位。
Wikipedia article on UTF-8 解释了 UTF-8 编码的工作原理。
我建议暂时添加如下内容:
writeln('text[', i, '] = ''', text[i], ''' = ', ord(s[i]));
在 for
循环的 begin
之后,您可以看到每个字符的值。
这说明了您遇到的问题,但没有说明解决方法。这取决于您的 Pascal 实现对非 ASCII 文本的支持类型。据我所知,Pascal 语言本身没有这样的支持,但是一些特定的实现mmmight.
现在我正试图在文本中找到最长的句子并打印出字符数,包括空格和类似的东西。问题是当我遇到像“š”或“á”这样的字符时,它会将它们计数两次。在那些情况下,我尝试减去一个,但这似乎也不起作用,因为它也将它们减去两次。知道我该如何解决吗?这是计数器的代码。
for i:=1 to length(text) do
case text[i] of
'.','!','?': begin
if len>p2 then p2:=len;
len:=0
end;
else inc(len);
end;
p2 是最长句子的计数器,len 是当前句子。
这对我来说适用于 ANSI 字符,包括带有变音符号的字符。由于您没有提到任何特定的字符集,并且您的问题被简单地标记为 pascal,它应该也适用于您。如果您正在处理其他字符集,那么您需要指出您正在使用哪个特定的 Pascal 编译器,因为对多字节字符的支持在各种 Pascal 方言之间有所不同。
function LongestSentenceCharCount(const Text: string): Integer;
var
Len: Integer;
LongLen: Integer;
i, CurrLen: Integer;
begin
Len := Length(Text);
CurrLen := 0;
LongLen := 0;
for I := 1 to Len do
begin
if Text[i] in ['.', '!', '?'] then
begin
if CurrLen > LongLen then
LongLen := CurrLen;
CurrLen := 0;
end
else
Inc(CurrLen);
end;
Result := LongLen;
end;
处理UTF-8、Unicode等多字节字符集-
根据 Seppy Bloom(当时是 Embarcadero RTL/VCL 的团队负责人)捐赠给 Cary Jensen 的白皮书 (PDF) Delphi Unicode Migration for Mere Mortals: Stories and Advice from the Front Lines 的一些代码,您可以使用一些自 Vista 及更高版本以来,Windows 中提供了规范化功能。我已经调整了上面的函数以使用来自 Seppy(包含在下面)的代码,以及一个示例应用程序来演示如何使用它。该代码是在 Delphi 10.1 Berlin 中开发、编译和测试的,因此如果您使用不同的编译器,则必须对其进行调整,如果您不是 运行 在 Windows Vista 或更高版本下。
program Project1;
{$APPTYPE CONSOLE}
uses
System.SysUtils, WinAPI.Windows;
const
NormalizationOther = 0;
NormalizationC = 1;
NormalizationD = 2;
NormalizationKC = 5;
NormalizationKD = 6;
function IsNormalizedString(NormForm: Integer; lpString: LPCWSTR;
cwLength: Integer): BOOL; stdcall; external 'Normaliz.dll';
function NormalizeString(NormForm: Integer; lpSrcString: LPCWSTR;
cwSrcLength: Integer; lpDstString: LPWSTR;
cwDstLength: Integer): Integer; stdcall; external 'Normaliz.dll';
function NormalizedStringLength(const Str: string): Integer;
var
Buf: string;
begin
if not IsNormalizedString(NormalizationC, PChar(Str), -1) then
begin
SetLength(Buf, NormalizeString(NormalizationC, PChar(Str),
Length(Str), nil, 0));
Result := NormalizeString(NormalizationC, PChar(Str),
Length(Str), PChar(Buf), Length(Buf));
end
else
Result := Length(Str);
end;
function LongestSentenceLen(const Text: string): Integer;
var
Len: Integer;
i, CurrLen: Integer;
begin
Len := Length(Text);
CurrLen := 0;
Result := 0;
for i := 1 to Len do
begin
// Replaces 'if Text[i] in ['.', '!', '?']', which will work
// but generates a compiler warning.
if CharInSet(Text[i], ['.', '!', '?']) then
begin
if CurrLen > Result then
Result := CurrLen;
CurrLen := 0;
end
else
Inc(CurrLen, NormalizedStringLength(Text[i]));
end;
end;
var
Test: string;
begin
Test := 'Ahoj, jak se máš? Hello World.';
WriteLn(Test);
WriteLn(Format('Longest: %d', [LongestSentenceLen(Test)]));
ReadLn;
end.
上面的输出是
Ahoj, jak se más? Hello World.
Longest: 16
最近我只在我提到的在线编译器中处理这个问题。我在其他任何地方都试过(免费的 Pascal 和 Turbo Pascal)它工作得很好。
谢谢你的帮助,我认为不同的编译器不会有什么不同。
您没有说明输入文本的表示方式,但您看到的症状与 UTF-8 输入一致。
ASCII 是一个 7 位字符集,不包含任何重音字母。您的变量 text
大概是一个字符数组。对于像 Ahoj, jak se mas?
这样的字符串,每个字符在数组中占据一个位置。对于像 Ahoj, jak se máš?
这样的字符串,'á'
和 'š'
字符在 ASCII 范围之外,每个字符表示为 2 个字节,因此在数组中有 2 个槽位。
Wikipedia article on UTF-8 解释了 UTF-8 编码的工作原理。
我建议暂时添加如下内容:
writeln('text[', i, '] = ''', text[i], ''' = ', ord(s[i]));
在 for
循环的 begin
之后,您可以看到每个字符的值。
这说明了您遇到的问题,但没有说明解决方法。这取决于您的 Pascal 实现对非 ASCII 文本的支持类型。据我所知,Pascal 语言本身没有这样的支持,但是一些特定的实现mmmight.