Day 4 - 运算符、字符串与控制台交互
建议用时:180-210 分钟
你将学会什么
- 表达式和运算符分别是什么
+、-、*、/、%怎么计算- 整数除法为什么会丢掉小数部分
=、==、!=、>、>=的区别&&、||、!怎么组合多个条件- 字符串怎么拼接、插值、裁剪、查找、替换
- 控制台输入为什么要先清洗再转换
- 如何写一个完整的“输入 -> 清洗 -> 转换 -> 计算 -> 输出”程序
本页只讲 C# 控制台基础,不讲任何界面框架。今天的重点是把“数据怎么处理”讲清楚。
本页固定顺序
- 先学第一部分:弄懂今天最小、最重要的知识,并运行短例子。
- 再学第二部分:把刚学的知识组合成一个完整例子。
- 然后做第三部分:自己跟着敲,再完成重复训练和每日小测。
- 最后做第四部分:先独立完成作业,再用完整答案检查。
从 Day 3 走到 Day 4
Day 3 学的是“程序根据条件决定走哪条路”,Day 4 学的是“条件里的数据到底怎么计算和整理”。
把两天连起来看:
Day 3:如果总价大于 100,就打折
↑
Day 4:总价怎么计算,折扣怎么计算,结果怎么显示你已经见过下面这些旧知识:
Console.ReadLine():读取用户输入。if:根据真假决定执行哪一段。return:输入不正确时提前结束。TryParse:尝试把文本转成数字。
今天真正新增的重点只有四组:
- 用
+ - * / %计算。 - 用比较和逻辑运算符得到
true或false。 - 用字符串插值和少量字符串方法整理文本。
- 用
F2、P0控制输出格式。
第一次学习时,不要求记住所有字符串方法。先掌握 Trim()、Length、ToUpper()、Contains(),其余方法知道“以后可以查”就够了。
今天的最低通过线
如果今天学完只能做到下面四件事,也算合格:
- 能解释
10 / 3为什么是3,10 % 3为什么是1。 - 能分清
=是赋值,==是比较。 - 能把
" keyboard "整理成"KEYBOARD"。 - 能算出
单价 * 数量,并用F2显示两位小数。
先达到最低通过线,再做折扣小票。不要一上来要求自己看懂整页。
第一部分:先学原理和最小知识
这一部分先解决“这是什么、为什么要这样写”。每看到一个短例子就亲手敲一遍并运行,不要先背完整程序。
今天先抓住什么
变量保存数据,运算符处理数据。程序真正有用的地方,往往就在“处理”这一步。
今天的主线是:
原始输入文本
-> Trim 清洗文本
-> TryParse 转成数字
-> 用运算符计算
-> 用条件判断保护边界
-> 格式化输出结果名词先讲清楚
| 名词 | 直接解释 | 例子 |
|---|---|---|
| 表达式 | 能算出结果的一段代码 | price * count |
| 运算符 | 执行计算、比较或逻辑判断的符号 | +、==、&& |
| 操作数 | 运算符两边参与运算的值 | price、count |
| 拼接 | 把字符串连起来 | "Hello " + name |
| 插值 | 在字符串里放变量 | $"你好,{name}" |
| 格式化 | 控制输出显示格式 | {total:F2} |
| 取余 | 得到除法后的余数 | 10 % 3 是 1 |
| 优先级 | 决定哪个运算先算 | * 通常先于 + |
表达式是什么
表达式就是能算出一个结果的代码。
decimal price = 20m;
int count = 3;
decimal total = price * count;
bool expensive = total >= 50m;
string line = $"总价: {total:F2}";
Console.WriteLine(total);
Console.WriteLine(expensive);
Console.WriteLine(line);这里有三种表达式:
| 表达式 | 结果类型 | 结果 |
|---|---|---|
price * count | decimal | 60 |
total >= 50m | bool | true |
$"总价: {total:F2}" | string | 一段文本 |
算术运算符
| 运算符 | 作用 | 例子 | 结果 |
|---|---|---|---|
+ | 加法 | 10 + 3 | 13 |
- | 减法 | 10 - 3 | 7 |
* | 乘法 | 10 * 3 | 30 |
/ | 除法 | 10 / 3 | 整数除法结果是 3 |
% | 取余 | 10 % 3 | 1 |
完整例子:
int a = 10;
int b = 3;
Console.WriteLine(a + b);
Console.WriteLine(a - b);
Console.WriteLine(a * b);
Console.WriteLine(a / b);
Console.WriteLine(a % b);输出:
13
7
30
3
1整数除法为什么是 3
10 / 3 如果两边都是 int,C# 会做整数除法,结果只保留整数部分。
int a = 10;
int b = 3;
Console.WriteLine(a / b);
Console.WriteLine((decimal)a / b);输出:
3
3.3333333333333333333333333333如果需要小数结果,至少要把其中一个数变成 decimal 或 double。
取余 % 有什么用
取余常用来判断能不能整除、分页、奇偶数。
int number = 17;
if (number % 2 == 0)
{
Console.WriteLine("偶数");
}
else
{
Console.WriteLine("奇数");
}17 % 2 等于 1,说明不能被 2 整除,所以是奇数。
运算优先级和括号
C# 会先算乘除,再算加减。
Console.WriteLine(2 + 3 * 4);
Console.WriteLine((2 + 3) * 4);输出:
14
20不要依赖别人猜你的优先级。业务计算里,想强调先算哪一段,就加括号。
复合赋值和自增
下面这些写法经常在循环和累计里出现:
int count = 0;
count = count + 1;
count += 1;
count++;
Console.WriteLine(count);输出:
3三次都让 count 加了 1。count++ 是最短写法,常用于计数。
比较运算符
比较运算符的结果一定是 bool。
int stock = 8;
Console.WriteLine(stock == 0);
Console.WriteLine(stock != 0);
Console.WriteLine(stock < 10);
Console.WriteLine(stock >= 10);输出:
False
True
True
False注意:= 是赋值,== 是比较。
逻辑运算符
多个条件要组合时,用逻辑运算符。
decimal price = 80m;
int count = 3;
decimal discount = 0.9m;
bool priceOk = price >= 0;
bool countOk = count > 0;
bool discountOk = discount > 0 && discount <= 1;
Console.WriteLine(priceOk && countOk && discountOk);输出:
True&& 表示所有条件都成立,|| 表示至少一个条件成立,! 表示取反。
字符串拼接和插值
拼接写法:
string name = "Tom";
int age = 18;
Console.WriteLine("姓名: " + name + ", 年龄: " + age);插值写法:
string name = "Tom";
int age = 18;
Console.WriteLine($"姓名: {name}, 年龄: {age}");两段输出一样,但插值更容易读。后面优先使用字符串插值。
字符串常用操作
字符串方法很多,但第一遍只练前四个。后面的写法先当作查询表,不要求背诵。
| 需求 | 写法 | 作用 |
|---|---|---|
| 去掉前后空格 | text.Trim() | 清理输入 |
| 获取字符数量 | text.Length | 检查输入长度 |
| 统一成大写 | text.ToUpper() | 统一显示或比较 |
| 判断是否包含 | text.Contains("Key") | 搜索 |
| 判断开头 | text.StartsWith("P-") | 判断编号前缀 |
| 判断结尾 | text.EndsWith(".csv") | 判断文件类型 |
| 替换内容 | text.Replace(" ", "-") | 替换空格、符号 |
| 转小写 | text.ToLower() | 搜索时统一比较 |
string text = " Keyboard ";
string clean = text.Trim();
Console.WriteLine(clean);
Console.WriteLine(clean.Length);
Console.WriteLine(clean.Contains("Key"));
Console.WriteLine(clean.StartsWith("Key"));
Console.WriteLine(clean.ToUpper());
Console.WriteLine(clean.Replace("Key", "Board"));输出:
Keyboard
8
True
True
KEYBOARD
Boardboard这些方法不会把原来的 text 直接改掉,它们会返回一个新的结果。要继续使用整理后的值,就用新变量接住。
再看一个“检查商品编号”的例子:
string rawCode = " P-2026-0001 ";
string code = rawCode.Trim().ToUpper();
if (!code.StartsWith("P-"))
{
Console.WriteLine("商品编号必须以 P- 开头");
return;
}
if (code.Length < 5)
{
Console.WriteLine("商品编号太短");
return;
}
Console.WriteLine($"整理后的编号: {code}");
Console.WriteLine($"编号长度: {code.Length}");输出:
整理后的编号: P-2026-0001
编号长度: 11这里的重点是:
Trim()先清理前后空格。ToUpper()统一大小写。StartsWith("P-")判断编号前缀。Length检查编号是不是明显太短。
把文本按横线拆成多段需要数组知识,安排在 Day 6 学完以后再练。今天不要提前背 Split 和下标。
格式化输出
金额常用两位小数:
decimal total = 59.7m;
Console.WriteLine($"{total:F2}");输出:
59.70百分比常用 P0:
decimal discount = 0.8m;
Console.WriteLine($"{discount:P0}");输出:
80%今天写代码时按这个顺序
- 原始输入变量用
xxxText,例如priceText。 - 文本先判断空值或格式。
- 需要计算时,用
TryParse转成数字。 - 金额用
decimal,数量用int。 - 用括号明确复杂计算顺序。
- 用
F2输出金额,用P0输出百分比。 - 输出前把字符串
Trim()。
第二部分:把知识组合成完整例子
前面已经学过最小知识。现在把它们组合起来,先读懂执行顺序,再完整敲一遍。今天最终要写一个更完整的小票程序:输入商品、单价、数量、折扣,再输出计算结果。
第一次看这段程序时,只做两件事:
- 看它向用户读取了哪四项数据。
- 看最后输出了哪三个计算结果。
中间暂时看不懂的判断可以先跳过。第三部分会从短代码开始,一段一段把它拼出来。
| 代码部分 | 属于哪天 | 第一次是否必须看懂 |
|---|---|---|
Console.ReadLine() | Day 2 旧知识 | 是 |
if、return | Day 3 旧知识 | 是 |
TryParse(..., out ...) | Day 2 旧知识 | 知道它在转换即可 |
price * count | Day 4 新知识 | 是 |
originalTotal * discount | Day 4 新知识 | 是 |
{value:F2}、{value:P0} | Day 4 新知识 | 是 |
最终你要写出这个程序
Console.Write("商品名称: ");
string? nameText = Console.ReadLine();
Console.Write("单价: ");
string? priceText = Console.ReadLine();
Console.Write("数量: ");
string? countText = Console.ReadLine();
Console.Write("折扣,例如 0.9 表示九折: ");
string? discountText = Console.ReadLine();
if (string.IsNullOrWhiteSpace(nameText))
{
Console.WriteLine("商品名称不能为空");
return;
}
if (!decimal.TryParse(priceText, out decimal price))
{
Console.WriteLine("单价必须是数字");
return;
}
if (!int.TryParse(countText, out int count))
{
Console.WriteLine("数量必须是整数");
return;
}
if (!decimal.TryParse(discountText, out decimal discount))
{
Console.WriteLine("折扣必须是数字");
return;
}
if (price < 0 || count <= 0 || discount <= 0 || discount > 1)
{
Console.WriteLine("单价、数量或折扣范围不正确");
return;
}
string name = nameText.Trim();
decimal originalTotal = price * count;
decimal finalTotal = originalTotal * discount;
decimal saved = originalTotal - finalTotal;
Console.WriteLine("----- 小票 -----");
Console.WriteLine($"商品: {name}");
Console.WriteLine($"单价: {price:F2}");
Console.WriteLine($"数量: {count}");
Console.WriteLine($"折扣: {discount:P0}");
Console.WriteLine($"原价合计: {originalTotal:F2}");
Console.WriteLine($"优惠金额: {saved:F2}");
Console.WriteLine($"应付金额: {finalTotal:F2}");正常输入:
商品名称: Keyboard
单价: 100
数量: 3
折扣,例如 0.9 表示九折: 0.8
----- 小票 -----
商品: Keyboard
单价: 100.00
数量: 3
折扣: 80%
原价合计: 300.00
优惠金额: 60.00
应付金额: 240.00今天要理解的是:这些计算和判断不是凭感觉写的,每个符号都有明确含义。
第三部分:跟着敲代码
从这里开始动手。每个例子都可以直接放进 Program.cs 运行。
每个例子按三遍练:第一遍照着敲并运行;第二遍只看标题重新写;第三遍改一个数字、条件或输入,再预测结果。不要复制粘贴。
动手前先做这 3 件事
- 打开控制台项目,确认
dotnet run能运行。 - 每做一个例子,就把
Program.cs旧内容替换掉。 - 每次只改一个数字或一行输入,看结果怎么变。
例子 1:数字运算和取余
int total = 23;
int pageSize = 5;
int fullPages = total / pageSize;
int remaining = total % pageSize;
Console.WriteLine($"完整页数: {fullPages}");
Console.WriteLine($"剩余数量: {remaining}");预期输出:
完整页数: 4
剩余数量: 3例子 2:整数除法和小数除法
int a = 10;
int b = 3;
Console.WriteLine(a / b);
Console.WriteLine((decimal)a / b);预期输出:
3
3.3333333333333333333333333333例子 3:字符串整理
Console.Write("请输入商品名称: ");
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
{
Console.WriteLine("商品名称不能为空");
return;
}
string name = input.Trim();
Console.WriteLine($"整理后的名称: {name}");
Console.WriteLine($"字符数量: {name.Length}");
Console.WriteLine($"大写名称: {name.ToUpper()}");输入 keyboard 时,会输出整理后的名称和长度。
例子 4:比较库存状态
Console.Write("请输入库存数量: ");
string? input = Console.ReadLine();
if (!int.TryParse(input, out int stock))
{
Console.WriteLine("库存必须是整数");
return;
}
if (stock == 0)
{
Console.WriteLine("缺货");
}
else if (stock < 10)
{
Console.WriteLine("库存偏低");
}
else
{
Console.WriteLine("库存充足");
}分别输入 0、5、20,观察三个分支。
例子 5:金额和折扣计算
decimal price = 100m;
int count = 3;
decimal discount = 0.8m;
decimal originalTotal = price * count;
decimal finalTotal = originalTotal * discount;
decimal saved = originalTotal - finalTotal;
Console.WriteLine($"原价合计: {originalTotal:F2}");
Console.WriteLine($"折扣: {discount:P0}");
Console.WriteLine($"优惠金额: {saved:F2}");
Console.WriteLine($"应付金额: {finalTotal:F2}");预期输出:
原价合计: 300.00
折扣: 80%
优惠金额: 60.00
应付金额: 240.00例子 6:完整输入、清洗、转换、计算
Console.Write("商品名称: ");
string? nameText = Console.ReadLine();
Console.Write("单价: ");
string? priceText = Console.ReadLine();
Console.Write("数量: ");
string? countText = Console.ReadLine();
if (string.IsNullOrWhiteSpace(nameText))
{
Console.WriteLine("商品名称不能为空");
return;
}
if (!decimal.TryParse(priceText, out decimal price))
{
Console.WriteLine("单价必须是数字");
return;
}
if (!int.TryParse(countText, out int count))
{
Console.WriteLine("数量必须是整数");
return;
}
string name = nameText.Trim();
decimal total = price * count;
Console.WriteLine($"{name} x {count} = {total:F2}");输入 Keyboard、19.9、3,输出:
Keyboard x 3 = 59.70例子 7:整理并检查商品编号
Console.Write("商品编号,例如 P-2026-0001: ");
string? codeText = Console.ReadLine();
if (string.IsNullOrWhiteSpace(codeText))
{
Console.WriteLine("商品编号不能为空");
return;
}
string code = codeText.Trim().ToUpper();
if (!code.StartsWith("P-"))
{
Console.WriteLine("商品编号必须以 P- 开头");
return;
}
if (code.Length < 5)
{
Console.WriteLine("商品编号太短");
return;
}
Console.WriteLine($"整理后的编号: {code}");
Console.WriteLine($"编号长度: {code.Length}");输入:
p-2026-0001输出:
整理后的编号: P-2026-0001
编号长度: 11常见错误和修法
| 错误 | 为什么错 | 修法 |
|---|---|---|
| 字符串拼接时漏空格 | 输出结果不易读 | 用插值字符串 $"名称: {name}" |
调用 Trim() 后仍输出旧变量 | 字符串方法返回新字符串 | 用变量接住 Trim() 的结果 |
忘记区分 = 和 == | 一个是赋值,一个是比较 | 读成“放进去”和“是不是” |
| 搜索时大小写不一致 | 同一文本可能匹配失败 | 比较前统一 ToLower() |
没有处理 ReadLine() 的空值 | 后续调用方法可能出错 | 先用空合并或空白判断 |
每日小测
先把答案写在纸上或注释里,再看下面的参考答案。
1. 预测输出
下面两行分别输出什么?
Console.WriteLine(17 / 5);
Console.WriteLine(17 % 5);2. 分清赋值和比较
下面哪一行是“把 10 放进 stock”,哪一行是“判断 stock 是否等于 10”?
stock = 10;
stock == 10;3. 用人话读条件
请用中文读出这个条件:
price >= 0 && count > 04. 找出字符串问题
下面代码为什么仍然输出前后带空格的原文本?
string text = " mouse ";
text.Trim();
Console.WriteLine(text);5. 排处理顺序
把下面五步按正确顺序排列:
计算总价
读取文本
输出结果
TryParse 转换
检查数据范围参考答案
- 输出
3和2。整数除法保留整数部分,取余得到余数。 stock = 10是赋值;stock == 10是比较,比较结果是bool。- 单价大于等于 0,并且数量大于 0。
- 字符串不会被
Trim()原地修改。应该写string clean = text.Trim();,再输出clean。 - 读取文本 ->
TryParse转换 -> 检查数据范围 -> 计算总价 -> 输出结果。
如果第 1、2、5 题答错,先不要做作业,回看“算术运算符”“比较运算符”和“今天写代码时按这个顺序”。
上位机专项练习
设备原始值经常需要换算、比较、格式化和拼接成界面文字。运算符和字符串就是最基础的数据处理工具。
下面 3 个例子都要亲手敲。先运行原代码,再完成每个例子后面的改动任务。
专项例子 1:把原始值换算成工程值
int rawValue = 2048;
double engineeringValue = rawValue / 4095.0 * 100.0;
Console.WriteLine($"工程值: {engineeringValue:F2}%");运行结果或界面效果:
工程值: 50.01%改动任务: 把 rawValue 改成 4095,结果应该接近 100%。
专项例子 2:组合报警条件
double pressure = 1.8;
bool isOnline = true;
bool hasAlarm = isOnline && pressure > 1.5;
Console.WriteLine($"是否报警: {hasAlarm}");运行结果或界面效果:
是否报警: True改动任务: 把 isOnline 改成 false,理解 && 的作用。
专项例子 3:整理设备标签
string area = "A区";
int deviceNumber = 7;
string tag = $"{area}-TEMP-{deviceNumber:D3}";
Console.WriteLine(tag);运行结果或界面效果:
A区-TEMP-007改动任务: 把编号改成 25,确认仍然显示三位。
第四部分:作业完整答案
这一部分给出当天作业的完整答案。先按第三部分做一遍,再用这里检查。
作业要求
写一个带折扣的小票程序,要求:
- 输入商品名称、单价、数量、折扣。
- 商品名称不能为空。
- 单价必须是数字,且不能小于 0。
- 数量必须是整数,且必须大于 0。
- 折扣必须是数字,范围是
0 < 折扣 <= 1。 - 输出原价合计、优惠金额、应付金额。
- 金额保留两位小数,折扣显示为百分比。
作业拆解
按这个顺序写:
- 用
ReadLine读取四个原始文本。 - 用
IsNullOrWhiteSpace判断名称。 - 用
decimal.TryParse转换单价和折扣。 - 用
int.TryParse转换数量。 - 用
||判断错误范围。 - 用
price * count算原价合计。 - 用
originalTotal * discount算折后金额。 - 用
originalTotal - finalTotal算优惠金额。
完整代码
Console.Write("商品名称: ");
string? nameText = Console.ReadLine();
Console.Write("单价: ");
string? priceText = Console.ReadLine();
Console.Write("数量: ");
string? countText = Console.ReadLine();
Console.Write("折扣,例如 0.9 表示九折: ");
string? discountText = Console.ReadLine();
if (string.IsNullOrWhiteSpace(nameText))
{
Console.WriteLine("商品名称不能为空");
return;
}
if (!decimal.TryParse(priceText, out decimal price))
{
Console.WriteLine("单价必须是数字");
return;
}
if (!int.TryParse(countText, out int count))
{
Console.WriteLine("数量必须是整数");
return;
}
if (!decimal.TryParse(discountText, out decimal discount))
{
Console.WriteLine("折扣必须是数字");
return;
}
if (price < 0)
{
Console.WriteLine("单价不能小于 0");
return;
}
if (count <= 0)
{
Console.WriteLine("数量必须大于 0");
return;
}
if (discount <= 0 || discount > 1)
{
Console.WriteLine("折扣必须大于 0 且小于等于 1");
return;
}
string name = nameText.Trim();
decimal originalTotal = price * count;
decimal finalTotal = originalTotal * discount;
decimal saved = originalTotal - finalTotal;
Console.WriteLine("----- 小票 -----");
Console.WriteLine($"商品: {name}");
Console.WriteLine($"单价: {price:F2}");
Console.WriteLine($"数量: {count}");
Console.WriteLine($"折扣: {discount:P0}");
Console.WriteLine($"原价合计: {originalTotal:F2}");
Console.WriteLine($"优惠金额: {saved:F2}");
Console.WriteLine($"应付金额: {finalTotal:F2}");正确运行结果
正常输入:
商品名称: Keyboard
单价: 100
数量: 3
折扣,例如 0.9 表示九折: 0.8
----- 小票 -----
商品: Keyboard
单价: 100.00
数量: 3
折扣: 80%
原价合计: 300.00
优惠金额: 60.00
应付金额: 240.00错误输入要分别测试:
商品名称为空:提示 商品名称不能为空
单价输入 abc:提示 单价必须是数字
数量输入 2.5:提示 数量必须是整数
折扣输入 2:提示 折扣必须大于 0 且小于等于 1你要能说清楚这 7 件事
+在数字上是加法,在字符串上是拼接。/用在两个整数上时是整数除法。%可以用来判断余数、分页和奇偶数。=是赋值,==是比较。&&是并且,||是或者,!是取反。Trim()返回整理后的新字符串。{value:F2}输出两位小数,{value:P0}输出百分比。