本课目标
完成本课后,你将能够:
- 掌握固定字符串
String与无界字符串Unbounded_String的使用 - 熟练进行字符串的查找、替换、分割与连接
- 理解字符串与数值的相互转换
- 学会使用
Ada.Strings.Fixed、Ada.Strings.Bounded、Ada.Strings.Unbounded三套处理方案 - 应用字符串处理解决实际问题(如解析配置文件、文本分析)
一、Ada 字符串家族
Ada 提供三种字符串类型,适应不同场景:
| 类型 | 包 | 特点 | 适用场景 |
|---|---|---|---|
String | 内置(无额外包) | 固定长度,编译时确定 | 长度已知的小字符串 |
Bounded_String | Ada.Strings.Bounded | 长度有上限,运行时可变 | 长度有限但可变 |
Unbounded_String | Ada.Strings.Unbounded | 长度无上限,动态分配 | 长度未知或变化频繁 |
-- 固定字符串(最常用)
S1 : String (1 .. 10); -- 长度固定为10
S2 : constant String := "Hello"; -- 长度由字面量决定,不可变
-- 无界字符串(最灵活)
with Ada.Strings.Unbounded;
use Ada.Strings.Unbounded;
S3 : Unbounded_String := To_Unbounded_String ("Hello");
S4 : Unbounded_String := Null_Unbounded_String;
二、固定字符串(String)
2.1 声明与初始化
-- 声明并初始化
S1 : String := "Ada";
S2 : String (1 .. 5) := "Hello";
S3 : String (1 .. 3) := ('A', 'd', 'a'); -- 字符数组形式
-- 未初始化,需后续赋值
S4 : String (1 .. 20);
S4 (1 .. 5) := "World";
2.2 字符串连接
使用 & 运算符:
Full : constant String := "Hello" & " " & "World"; -- "Hello World"
Prefix : String := "Ada";
Result : String := Prefix & " is great"; -- "Ada is great"
2.3 字符串比较
直接使用关系运算符(按字典序):
if "abc" < "abd" then -- True
if "Ada" = "ADA" then -- False(大小写敏感)
if "Ada" /= "ada" then -- True
2.4 字符串属性与遍历
S : String := "Ada";
Len : constant Integer := S'Length; -- 3
First : constant Integer := S'First; -- 1
Last : constant Integer := S'Last; -- 3
-- 遍历字符
for I in S'Range loop
Ada.Text_IO.Put (S (I));
end loop;
三、无界字符串(Unbounded_String)
3.1 基本操作
with Ada.Strings.Unbounded;
with Ada.Strings.Unbounded.Text_IO; -- 用于输入输出
use Ada.Strings.Unbounded;
procedure Unbounded_Demo is
U : Unbounded_String;
begin
-- 赋值
U := To_Unbounded_String ("Hello");
U := U & " World"; -- 连接
U := "New " & U; -- 连接结果再赋值
-- 输出
Ada.Strings.Unbounded.Text_IO.Put_Line (U);
-- 获取固定字符串形式
declare
Fixed : String := To_String (U);
begin
Ada.Text_IO.Put_Line (Fixed);
end;
end Unbounded_Demo;
3.2 常用函数
| 函数 | 作用 |
|---|---|
To_Unbounded_String (S : String) | 将固定字符串转为无界字符串 |
To_String (U : Unbounded_String) | 将无界字符串转为固定字符串 |
Length (U : Unbounded_String) | 返回字符数 |
Append (U : in out Unbounded_String; S : String) | 追加 |
& 运算符 | 连接(返回新无界字符串) |
"="、"/="、"<" 等 | 比较操作(与固定字符串和无界字符串均可比较) |
3.3 输入输出
with Ada.Strings.Unbounded.Text_IO;
procedure U_IO is
U : Unbounded_String;
begin
Ada.Text_IO.Put ("Enter text: ");
Ada.Strings.Unbounded.Text_IO.Get_Line (U);
Ada.Strings.Unbounded.Text_IO.Put_Line ("You entered: " & U);
end U_IO;
四、字符串查找与索引
4.1 基本查找
使用 Ada.Strings.Fixed 中的函数(针对固定字符串):
with Ada.Strings.Fixed;
procedure Search_Demo is
S : String := "Hello Ada World";
Pos : Natural;
begin
-- 查找子串
Pos := Ada.Strings.Fixed.Index (S, "Ada");
if Pos > 0 then
Ada.Text_IO.Put_Line ("Found at position" & Integer'Image (Pos));
end if;
-- 从指定位置开始查找
Pos := Ada.Strings.Fixed.Index (S, "o", Ada.Strings.Forward, 3);
-- 反向查找
Pos := Ada.Strings.Fixed.Index (S, "o", Ada.Strings.Backward);
end Search_Demo;
4.2 判断前缀/后缀
if Ada.Strings.Fixed.Head (S, 4) = "Hell" then ... -- 取前4个字符
if Ada.Strings.Fixed.Tail (S, 5) = "World" then ... -- 取后5个字符
-- Ada 2012 更方便的扩展(需 GNAT)
-- if S'Starts_With ("Hello") then ...
4.3 无界字符串的查找
Ada.Strings.Unbounded 提供类似函数:
U : Unbounded_String := To_Unbounded_String ("Find the needle in haystack");
Pos : Natural := Index (U, "needle"); -- 返回位置
五、字符串替换与修剪
5.1 替换子串
with Ada.Strings.Fixed;
procedure Replace_Demo is
S : String := "Hello World";
Result : String (1 .. S'Length);
begin
-- 替换指定范围
Result := S;
Result (6 .. 10) := "Ada "; -- 注意长度匹配
-- 使用 Replace_Slice
Result := Ada.Strings.Fixed.Replace_Slice (S, 6, 10, "Ada");
-- "Hello Ada"
end Replace_Demo;
5.2 删除与修剪
S : String := " Hello ";
-- 删除首尾空格
Trimmed : String := Ada.Strings.Fixed.Trim (S, Ada.Strings.Both);
-- Trim 参数:Left(左侧)、Right(右侧)、Both(两侧)
-- 删除指定范围
Short : String := Ada.Strings.Fixed.Delete (S, 1, 3);
5.3 大小写转换
Ada 标准库不直接提供,可通过 Ada.Characters.Handling 逐个字符转换:
with Ada.Characters.Handling;
use Ada.Characters.Handling;
function To_Upper (S : String) return String is
Result : String (S'Range);
begin
for I in S'Range loop
Result (I) := To_Upper (S (I));
end loop;
return Result;
end To_Upper;
六、字符串与数值转换
6.1 数值转字符串
-- 方法1:使用 'Image 属性
S1 : String := Integer'Image (42); -- " 42"(前导空格)
S2 : String := Float'Image (3.14); -- " 3.14000E+00"
-- 方法2:使用 Ada.Strings.Fixed.Trim 去除空格
S3 : String := Ada.Strings.Fixed.Trim (Integer'Image (42), Ada.Strings.Left);
-- "42"
6.2 字符串转数值
-- 使用 'Value 属性
N : Integer := Integer'Value ("42");
F : Float := Float'Value ("3.14");
-- 安全转换(捕获异常)
declare
N : Integer;
begin
N := Integer'Value (Input_String);
exception
when Constraint_Error =>
Ada.Text_IO.Put_Line ("无效数字");
end;
6.3 使用 Ada.Text_IO 进行转换
-- 从字符串读取数值(需要临时文件或 Ada.Strings.Fixed 等技巧)
-- 更常用的是直接使用 'Value
七、正则表达式简介(GNAT.Regpat)
GNAT 提供 GNAT.Regpat 包支持正则表达式,用于复杂模式匹配。
with GNAT.Regpat;
procedure Regex_Demo is
use GNAT.Regpat;
Pattern : Pattern_Matcher := Compile ("[0-9]+"); -- 匹配数字串
S : String := "The answer is 42.";
Matches : Match_Array (0 .. 0);
begin
Match (Pattern, S, Matches);
if Matches (0) /= No_Match then
declare
Num_Str : String := S (Matches (0).First .. Matches (0).Last);
begin
Ada.Text_IO.Put_Line ("Found number: " & Num_Str);
end;
end if;
end Regex_Demo;
注意:正则表达式功能强大但依赖于 GNAT 扩展,跨平台移植性需注意。
八、完整示例:配置文件解析器
-- 文件名: config_parser.adb
-- 功能:解析简单的 key=value 配置文件
with Ada.Text_IO;
with Ada.Strings.Fixed;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Strings.Unbounded.Text_IO;
procedure Config_Parser is
type Config_Entry is record
Key : Unbounded_String;
Value : Unbounded_String;
end record;
Max_Entries : constant := 100;
Config_List : array (1 .. Max_Entries) of Config_Entry;
Entry_Count : Integer := 0;
-- 去除字符串首尾空格
function Trim (S : String) return String is
begin
return Ada.Strings.Fixed.Trim (S, Ada.Strings.Both);
end Trim;
-- 解析一行 "key = value"
procedure Parse_Line (Line : String) is
Eq_Pos : Natural;
Key_Str, Value_Str : String (1 .. Line'Length);
Key_Len, Value_Len : Integer;
begin
-- 查找等号
Eq_Pos := Ada.Strings.Fixed.Index (Line, "=");
if Eq_Pos = 0 then
return; -- 跳过无效行
end if;
-- 提取 key 和 value
Key_Str (1 .. Eq_Pos - 1) := Line (Line'First .. Eq_Pos - 1);
Key_Len := Eq_Pos - 1;
Value_Str (1 .. Line'Length - Eq_Pos) := Line (Eq_Pos + 1 .. Line'Last);
Value_Len := Line'Length - Eq_Pos;
-- 去除空格后存储
Entry_Count := Entry_Count + 1;
Config_List (Entry_Count) := (
Key => To_Unbounded_String (Trim (Key_Str (1 .. Key_Len))),
Value => To_Unbounded_String (Trim (Value_Str (1 .. Value_Len)))
);
end Parse_Line;
-- 根据 key 获取 value
function Get_Value (Key : String) return String is
begin
for I in 1 .. Entry_Count loop
if To_String (Config_List (I).Key) = Key then
return To_String (Config_List (I).Value);
end if;
end loop;
return "";
end Get_Value;
-- 从文件加载配置
procedure Load_Config (Filename : String) is
File : Ada.Text_IO.File_Type;
Line : String (1 .. 200);
Last : Integer;
begin
Ada.Text_IO.Open (File, Ada.Text_IO.In_File, Filename);
while not Ada.Text_IO.End_Of_File (File) loop
Ada.Text_IO.Get_Line (File, Line, Last);
Parse_Line (Line (1 .. Last));
end loop;
Ada.Text_IO.Close (File);
end Load_Config;
begin
-- 假设有配置文件 config.txt,内容如:
-- host = localhost
-- port = 8080
-- debug = true
Load_Config ("config.txt");
Ada.Text_IO.Put_Line ("Host: " & Get_Value ("host"));
Ada.Text_IO.Put_Line ("Port: " & Get_Value ("port"));
Ada.Text_IO.Put_Line ("Debug: " & Get_Value ("debug"));
end Config_Parser;
九、本课总结
- Ada 有三种字符串类型:
String(固定长度)、Bounded_String(有限可变)、Unbounded_String(无限可变) Unbounded_String最灵活,适合大多数动态字符串需求Ada.Strings.Fixed提供固定字符串的查找、替换、修剪等操作Ada.Strings.Unbounded提供无界字符串的类似操作- 字符串与数值转换通过
'Image和'Value实现 - GNAT 正则表达式扩展支持复杂模式匹配
十、课后练习
-
字符串反转:编写函数
Reverse (S : String) return String,返回反转后的字符串。 -
无界字符串统计:从标准输入读取多行文本,统计总字符数、单词数(以空格分隔)、行数。
-
配置文件扩展:修改配置解析器,支持注释行(以
#开头)和空行跳过。 -
数值转换:编写程序读取用户输入的字符串,尝试转换为整数,若失败则提示重新输入。
-
简单分词器:给定一个字符串,按空格分割成单词列表,并去除标点符号。
十一、下节预告
第20课|泛型编程入门
我们将:
- 理解泛型的概念与优势
- 掌握泛型包的声明与实例化
- 学习泛型子程序的编写
- 应用泛型实现通用容器(如栈、队列)
关键术语表
String:Ada 内置的固定长度字符串类型
Unbounded_String:可动态扩展的字符串类型,定义在Ada.Strings.Unbounded
Bounded_String:长度有上限的可变字符串,定义在Ada.Strings.Bounded
To_Unbounded_String:将固定字符串转换为无界字符串的函数
To_String:将无界字符串转换为固定字符串的函数
Index:查找子串位置的函数
Trim:删除字符串首尾空格或指定字符的函数
Replace_Slice:替换字符串中某一段的函数
'Image:将数值转换为字符串的属性
'Value:将字符串转换为数值的属性
GNAT.Regpat:GNAT 提供的正则表达式包