flutter聊天界面-TextField输入框实现@功能等匹配正则表达式展示高亮功能
flutter聊天界面-TextField输入框实现@功能等匹配正则表达式展示高亮功能
一、简要描述
描述:
最近有位朋友讨论的时候,提到了输入框的高亮展示。在flutter TextField中需要插入特殊样式的标签,比如:“请 @张三 回答一下”,这一串字符在TextField中输入,当输入@时 弹出好友列表选择,然后将 “@张三”高亮显示在TextField中。
效果图如下
视频效果
flutter聊天界面-TextField输入框实现@功能
昨天整理的文中,简单实用TextEditingController的buildTextSpan时候,直接修改代码
List<InlineSpan> textSpans = RichTextHelper.getRichText(value.text);if (composingRegionOutOfRange) {return TextSpan(style: style, children: textSpans);}
会出现光标输入的问题,这里修改了一下,完善了一下。
大家可以使用rich_text_controller
来实现,查看rich_text_controller源码可以看到,RichTextController继承TextEditingController,重写了buildTextSpan。经过我在iPhone上测试,当输入@汉字的时候,对中文兼容会有问题,这里做一下修改完善修改。
二、TextEditingController的buildTextSpan方法
在TextEditingController中buildTextSpan方法中,我们可以看到,该方法中的代码
composingRegionOutOfRange:仅有输入完成的字
在最后一部分的代码中含有未输入完成的字
final TextStyle composingStyle = style?.merge(const TextStyle(decoration: TextDecoration.underline))?? const TextStyle(decoration: TextDecoration.underline);return TextSpan(style: style,children: <TextSpan>[TextSpan(text: value.composing.textBefore(value.text)),TextSpan(style: composingStyle,text: value.composing.textInside(value.text),),TextSpan(text: value.composing.textAfter(value.text)),],);
-
composingStyle未输入完成的字的样式,可以自己做下修改。
-
value.composing.textBefore:当前输入前面的字。
-
value.composing.textAfter:当前输入后面的字。
当输入过程中,我们将value.composing.textBefore,value.composing.textAfter匹配高亮即可
代码如下
value.composing.textBefore
TextSpan(style: style, children: buildRegExpSpan(context: context, text: value.composing.textBefore(value.text))),
value.composing.textAfter
TextSpan(style: style, children: buildRegExpSpan(context: context, text: value.composing.textAfter(value.text))),
匹配正则表达式
List<TextSpan> buildRegExpSpan({required BuildContext context,TextStyle? style,required String? text}) {List<TextSpan> children = [];if (!(text != null && text.isNotEmpty)) {return children;}final matches = <String>{};List<Map<String, List<int>>> matchIndex = [];// Validating with REGEXRegExp? allRegex;allRegex = patternMatchMap != null? RegExp(patternMatchMap?.keys.map((e) => e.pattern).join('|') ?? "",caseSensitive: regExpCaseSensitive,dotAll: regExpDotAll,multiLine: regExpMultiLine,unicode: regExpUnicode): null;// Validating with StringsRegExp? stringRegex;stringRegex = stringMatchMap != null? RegExp(r'\b' + stringMatchMap!.keys.join('|').toString() + r'+\$',caseSensitive: regExpCaseSensitive,dotAll: regExpDotAll,multiLine: regExpMultiLine,unicode: regExpUnicode): null;text.splitMapJoin(stringMatchMap == null ? allRegex! : stringRegex!,onNonMatch: (String span) {if (stringMatchMap != null &&children.isNotEmpty &&stringMatchMap!.keys.contains("${children.last.text}$span")) {final String? ks =stringMatchMap!["${children.last.text}$span"] != null? stringMatchMap?.entries.lastWhere((element) {return element.key.allMatches("${children.last.text}$span").isNotEmpty;}).key: '';children.add(TextSpan(text: span, style: stringMatchMap![ks!]));return span.toString();} else {children.add(TextSpan(text: span, style: style));return span.toString();}},onMatch: (Match m) {matches.add(m[0]!);final RegExp? k = patternMatchMap?.entries.firstWhere((element) {return element.key.allMatches(m[0]!).isNotEmpty;}).key;final String? ks = stringMatchMap?[m[0]] != null? stringMatchMap?.entries.firstWhere((element) {return element.key.allMatches(m[0]!).isNotEmpty;}).key: '';if (deleteOnBack!) {if ((isBack(text!, _lastValue) && m.end == selection.baseOffset)) {WidgetsBinding.instance.addPostFrameCallback((_) {children.removeWhere((element) => element.text! == text);text = text!.replaceRange(m.start, m.end, "");selection = selection.copyWith(baseOffset: m.end - (m.end - m.start),extentOffset: m.end - (m.end - m.start),);});} else {children.add(TextSpan(text: m[0],style: stringMatchMap == null? patternMatchMap![k]: stringMatchMap![ks],),);}} else {children.add(TextSpan(text: m[0],style: stringMatchMap == null? patternMatchMap![k]: stringMatchMap![ks],),);}final resultMatchIndex = matchValueIndex(m);if (resultMatchIndex != null && onMatchIndex != null) {matchIndex.add(resultMatchIndex);onMatchIndex!(matchIndex);}return (onMatch(List<String>.unmodifiable(matches)) ?? '');},);return children;}
这里使用的是rich_text_controller中的代码,做了相应的修改,输入@张三正则表达式正常高亮显示了。
整个text_field_controller代码如下
import 'package:flutter/material.dart';class TextFieldController extends TextEditingController {final Map<RegExp, TextStyle>? patternMatchMap;final Map<String, TextStyle>? stringMatchMap;final Function(List<String> match) onMatch;final Function(List<Map<String, List<int>>>)? onMatchIndex;final bool? deleteOnBack;String _lastValue = "";/// controls the caseSensitive property of the full [RegExp] used to pattern matchfinal bool regExpCaseSensitive;/// controls the dotAll property of the full [RegExp] used to pattern matchfinal bool regExpDotAll;/// controls the multiLine property of the full [RegExp] used to pattern matchfinal bool regExpMultiLine;/// controls the unicode property of the full [RegExp] used to pattern matchfinal bool regExpUnicode;bool isBack(String current, String last) {return current.length < last.length;}TextFieldController({String? text,this.patternMatchMap,this.stringMatchMap,required this.onMatch,this.onMatchIndex,this.deleteOnBack = false,this.regExpCaseSensitive = true,this.regExpDotAll = false,this.regExpMultiLine = false,this.regExpUnicode = false}): assert((patternMatchMap != null && stringMatchMap == null) ||(patternMatchMap == null && stringMatchMap != null)),super(text: text);/// Setting this will notify all the listeners of this [TextEditingController]/// that they need to update (it calls [notifyListeners]).set text(String newText) {value = value.copyWith(text: newText,selection: const TextSelection.collapsed(offset: -1),composing: TextRange.empty,);}/// Builds [TextSpan] from current editing value.TextSpan buildTextSpan({required BuildContext context,TextStyle? style,required bool withComposing}) {assert(!value.composing.isValid || !withComposing || value.isComposingRangeValid);// If the composing range is out of range for the current text, ignore it to// preserve the tree integrity, otherwise in release mode a RangeError will// be thrown and this EditableText will be built with a broken subtree.final bool composingRegionOutOfRange = !value.isComposingRangeValid || !withComposing;if (composingRegionOutOfRange) {List<TextSpan> children = [];final matches = <String>{};List<Map<String, List<int>>> matchIndex = [];// Validating with REGEXRegExp? allRegex;allRegex = patternMatchMap != null? RegExp(patternMatchMap?.keys.map((e) => e.pattern).join('|') ?? "",caseSensitive: regExpCaseSensitive,dotAll: regExpDotAll,multiLine: regExpMultiLine,unicode: regExpUnicode): null;// Validating with StringsRegExp? stringRegex;stringRegex = stringMatchMap != null? RegExp(r'\b' + stringMatchMap!.keys.join('|').toString() + r'+\$',caseSensitive: regExpCaseSensitive,dotAll: regExpDotAll,multiLine: regExpMultiLine,unicode: regExpUnicode): null;text.splitMapJoin(stringMatchMap == null ? allRegex! : stringRegex!,onNonMatch: (String span) {if (stringMatchMap != null &&children.isNotEmpty &&stringMatchMap!.keys.contains("${children.last.text}$span")) {final String? ks =stringMatchMap!["${children.last.text}$span"] != null? stringMatchMap?.entries.lastWhere((element) {return element.key.allMatches("${children.last.text}$span").isNotEmpty;}).key: '';children.add(TextSpan(text: span, style: stringMatchMap![ks!]));return span.toString();} else {children.add(TextSpan(text: span, style: style));return span.toString();}},onMatch: (Match m) {matches.add(m[0]!);final RegExp? k = patternMatchMap?.entries.firstWhere((element) {return element.key.allMatches(m[0]!).isNotEmpty;}).key;final String? ks = stringMatchMap?[m[0]] != null? stringMatchMap?.entries.firstWhere((element) {return element.key.allMatches(m[0]!).isNotEmpty;}).key: '';if (deleteOnBack!) {if ((isBack(text, _lastValue) && m.end == selection.baseOffset)) {WidgetsBinding.instance.addPostFrameCallback((_) {children.removeWhere((element) => element.text! == text);text = text.replaceRange(m.start, m.end, "");selection = selection.copyWith(baseOffset: m.end - (m.end - m.start),extentOffset: m.end - (m.end - m.start),);});} else {children.add(TextSpan(text: m[0],style: stringMatchMap == null? patternMatchMap![k]: stringMatchMap![ks],),);}} else {children.add(TextSpan(text: m[0],style: stringMatchMap == null? patternMatchMap![k]: stringMatchMap![ks],),);}final resultMatchIndex = matchValueIndex(m);if (resultMatchIndex != null && onMatchIndex != null) {matchIndex.add(resultMatchIndex);onMatchIndex!(matchIndex);}return (onMatch(List<String>.unmodifiable(matches)) ?? '');},);_lastValue = text;return TextSpan(style: style, children: children);}final TextStyle composingStyle = style?.merge(const TextStyle(decoration: TextDecoration.underline))?? const TextStyle(decoration: TextDecoration.underline);return TextSpan(children: <TextSpan>[TextSpan(style: style, children: buildRegExpSpan(context: context, text: value.composing.textBefore(value.text))),TextSpan(style: composingStyle,text: value.composing.textInside(value.text),),TextSpan(style: style, children: buildRegExpSpan(context: context, text: value.composing.textAfter(value.text))),],);}Map<String, List<int>>? matchValueIndex(Match match) {final matchValue = match[0]?.replaceFirstMapped('#', (match) => '');if (matchValue != null) {final firstMatchChar = match.start + 1;final lastMatchChar = match.end - 1;final compactMatch = {matchValue: [firstMatchChar, lastMatchChar]};return compactMatch;}return null;}List<TextSpan> buildRegExpSpan({required BuildContext context,TextStyle? style,required String? text}) {List<TextSpan> children = [];if (!(text != null && text.isNotEmpty)) {return children;}final matches = <String>{};List<Map<String, List<int>>> matchIndex = [];// Validating with REGEXRegExp? allRegex;allRegex = patternMatchMap != null? RegExp(patternMatchMap?.keys.map((e) => e.pattern).join('|') ?? "",caseSensitive: regExpCaseSensitive,dotAll: regExpDotAll,multiLine: regExpMultiLine,unicode: regExpUnicode): null;// Validating with StringsRegExp? stringRegex;stringRegex = stringMatchMap != null? RegExp(r'\b' + stringMatchMap!.keys.join('|').toString() + r'+\$',caseSensitive: regExpCaseSensitive,dotAll: regExpDotAll,multiLine: regExpMultiLine,unicode: regExpUnicode): null;text.splitMapJoin(stringMatchMap == null ? allRegex! : stringRegex!,onNonMatch: (String span) {if (stringMatchMap != null &&children.isNotEmpty &&stringMatchMap!.keys.contains("${children.last.text}$span")) {final String? ks =stringMatchMap!["${children.last.text}$span"] != null? stringMatchMap?.entries.lastWhere((element) {return element.key.allMatches("${children.last.text}$span").isNotEmpty;}).key: '';children.add(TextSpan(text: span, style: stringMatchMap![ks!]));return span.toString();} else {children.add(TextSpan(text: span, style: style));return span.toString();}},onMatch: (Match m) {matches.add(m[0]!);final RegExp? k = patternMatchMap?.entries.firstWhere((element) {return element.key.allMatches(m[0]!).isNotEmpty;}).key;final String? ks = stringMatchMap?[m[0]] != null? stringMatchMap?.entries.firstWhere((element) {return element.key.allMatches(m[0]!).isNotEmpty;}).key: '';if (deleteOnBack!) {if ((isBack(text!, _lastValue) && m.end == selection.baseOffset)) {WidgetsBinding.instance.addPostFrameCallback((_) {children.removeWhere((element) => element.text! == text);text = text!.replaceRange(m.start, m.end, "");selection = selection.copyWith(baseOffset: m.end - (m.end - m.start),extentOffset: m.end - (m.end - m.start),);});} else {children.add(TextSpan(text: m[0],style: stringMatchMap == null? patternMatchMap![k]: stringMatchMap![ks],),);}} else {children.add(TextSpan(text: m[0],style: stringMatchMap == null? patternMatchMap![k]: stringMatchMap![ks],),);}final resultMatchIndex = matchValueIndex(m);if (resultMatchIndex != null && onMatchIndex != null) {matchIndex.add(resultMatchIndex);onMatchIndex!(matchIndex);}return (onMatch(List<String>.unmodifiable(matches)) ?? '');},);return children;}
}
至此可以看到效果图中@张三 高亮显示了。
三、使用TextFieldController测试@张三 高亮
调整好TextFieldController后,我这里测试@张三 高亮
我们进行初始化TextFieldController
// Add a controllerlate TextFieldController _controller;void initState() {// TODO: implement initState_controller = TextFieldController(patternMatchMap: {////* Returns every Hashtag with red color//RegExp(r"@[^\s]+\s?"):TextStyle(color:Colors.green),////* Returns every Hashtag with red color//RegExp(r"\B#[a-zA-Z0-9]+\b"):TextStyle(color:Colors.red),////* Returns every Mention with blue color and bold style.//RegExp(r"\B@[a-zA-Z0-9]+\b"):TextStyle(fontWeight: FontWeight.w800 ,color:Colors.blue,),////* Returns every word after '!' with yellow color and italic style.//RegExp(r"\B![a-zA-Z0-9]+\b"):TextStyle(color:Colors.yellow, fontStyle:FontStyle.italic),// add as many expressions as you need!},//* starting v1.2.0// Now you have the option to add string Matching!// stringMatchMap: {// "String1":TextStyle(color: Colors.red),// "String2":TextStyle(color: Colors.yellow),// },//! Assertion: Only one of the two matching options can be given at a time!//* starting v1.1.0//* Now you have an onMatch callback that gives you access to a List<String>//* which contains all matched stringsonMatch: (List<String> matches){// Do something with matches.//! P.S// as long as you're typing, the controller will keep updating the list.},deleteOnBack: true,// You can control the [RegExp] options used:regExpUnicode: true,);super.initState();}
在TextField中使用TextFieldController。具体代码如下
TextField(minLines: 1,maxLines: null,keyboardType: TextInputType.multiline,textAlignVertical: TextAlignVertical.center,autofocus: true,focusNode: editFocusNode,controller: _controller,textInputAction: TextInputAction.send,decoration: InputDecoration(contentPadding: EdgeInsets.symmetric(vertical: 10, horizontal: 8.0),filled: true,isCollapsed: true,floatingLabelBehavior: FloatingLabelBehavior.never,hintText: "说点什么吧~",hintStyle: TextStyle(fontSize: 14,fontWeight: FontWeight.w400,fontStyle: FontStyle.normal,color: ColorUtil.hexColor(0xACACAC),decoration: TextDecoration.none,),enabledBorder: OutlineInputBorder(/*边角*/borderRadius: const BorderRadius.all(Radius.circular(5.0), //边角为30),borderSide: BorderSide(color: ColorUtil.hexColor(0xf7f7f7), //边框颜色为绿色width: 1, //边线宽度为1),),focusedBorder: OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(5.0), //边角为30),borderSide: BorderSide(color: ColorUtil.hexColor(0xECECEC), //边框颜色为绿色width: 1, //宽度为1),),),)
经过输入删除测试,输入的“@张三”高亮显示在TextField中正常了。
使用TextEditingController的buildTextSpan,可以查看:https://blog.csdn.net/gloryFlow/article/details/132889374
完善TextField输入框匹配正则表达式高亮显示,可以查看:https://blog.csdn.net/gloryFlow/article/details/132899084
四、小结
flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能。自定义修改TextEditingController。
内容较多,描述可能不准确,请见谅。
本文地址:https://blog.csdn.net/gloryFlow/article/details/132899084
学习记录,每天不停进步。
相关文章:

flutter聊天界面-TextField输入框实现@功能等匹配正则表达式展示高亮功能
flutter聊天界面-TextField输入框实现功能等匹配正则表达式展示高亮功能 一、简要描述 描述: 最近有位朋友讨论的时候,提到了输入框的高亮展示。在flutter TextField中需要插入特殊样式的标签,比如:“请 张三 回答一下”&#x…...

【C语言】指针的进阶(二)—— 回调函数的讲解以及qsort函数的使用方式
目录 1、函数指针数组 1.1、函数指针数组是什么? 1.2、函数指针数组的用途:转移表 2、扩展:指向函数指针的数组的指针 3、回调函数 3.1、回调函数介绍 3.2、回调函数的案例:qsort函数 3.2.1、回顾冒泡排序 3.2.1、什么是qso…...

Java集合之HashSet接口
Set Set接口、HashSet类、TreeSet类 Set(组、集):表示无序,元素不能重复的集合,组中的元素必须唯一 Set接口 Set接口定义了组/集/集合(Set)。他扩展了Collection接口,并声明了不允…...

uniapp----微信小程序 日历组件(周日历 月日历)【Vue3+ts+uView】
uniapp----微信小程序 日历组件(周日历&& 月日历)【Vue3tsuView】 用Vue3tsuView来编写日历组件;存在周日历和月日历两种显示方式;高亮显示当天日期,红点渲染有数据的日期,点击显示数据 1. calenda…...

【记录】深度学习环境配置(pytorch版)
1080面对Transformer连勉强也算不上了,还是要去用小组的卡 完整记一个环境配置,方便后面自用✍️ 目前要简单许多,因为显卡驱动已经装好,后安装的库版本与其对应即可。 nvidia-smi查看GPU信息 ** CUDA版本12.2 conda -V查询conda…...
如何将项目推送到GitHub中
将项目推送到 GitHub 仓库并管理相关操作,遵循以下步骤: 创建 GitHub 账户:如果您没有 GitHub 账户,首先需要在 GitHub 官网 上创建一个账户。 创建新仓库:在 GitHub 页面上,点击右上角的加号图标…...

数据库直连提示 No suitable driver found for jdbc:postgresql
背景:我在代码里使用直连的方式在数据库中创建数据库等,由于需要适配各个数据库服务所以我分别兼容了mysql、postgresql、oracal等。但是在使用过程中会出现错误: No suitable driver found for jdbc:postgresql 但是我再使用mysql的直连方式…...

Stability AI推出Stable Audio;ChatGPT:推荐系统的颠覆者
🦉 AI新闻 🚀 Stability AI推出Stable Audio,用户可以生成个性化音乐片段 摘要:Stability AI公司发布了一款名为Stable Audio的工具,用户可以根据自己的文本内容自动生成音乐或音频。免费版可生成最长20秒音乐片段&a…...

HTML中的<canvas>元素
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ canvas元素⭐ 用途⭐ 示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们…...

【论文阅读】MARS:用于自动驾驶的实例感知、模块化和现实模拟器
【论文阅读】MARS:用于自动驾驶的实例感知、模块化和现实模拟器 Abstract1 Introduction2 Method2.1 Scene Representation2.3 Towards Realistic Rendering2.4 Optimization3.1 Photorealistic Rendering3.2 Instance-wise Editing3.3 The blessing of moduler des…...
Leetcode 2856. Minimum Array Length After Pair Removals
Leetcode 2856. Minimum Array Length After Pair Removals 1. 解题思路2. 代码实现 题目链接:2856. Minimum Array Length After Pair Removals 1. 解题思路 这一题思路而言个人觉得还是挺有意思的,因为显然这道题没法直接用greedy的方法进行处理&am…...

深入了解Vue.js框架:构建现代化的用户界面
目录 一.Vue前言介绍 二.Vue.js框架的核心功能与特性 三.MVVM的介绍 四.Vue的生命周期 五.库与框架的区别 1.库(Library): 2.框架(Framework): 六.Vue常用指令演示 1.v-model 2.v-on:click&…...

力扣 -- 673. 最长递增子序列的个数
小算法: 通过一次遍历找到数组中最大值出现的次数: 利用这个小算法求解这道题就会非常简单了。 参考代码: class Solution { public:int findNumberOfLIS(vector<int>& nums) {int nnums.size();vector<int> len(n,1);auto…...
43.248.189.X网站提示风险,存在黑客攻击页面被篡改,改如何解决呢?
当用户百度搜索我们的网站,准备打开该网站时,访问页面提示风险,告知被黑客攻击并有被篡改的情况,有哪些方案可以查看解决问题? 当遇到网站提示风险到时候,可以考虑采用下面几个步骤来解决问题:…...

Java8中判断一个对象不为空存在一个类对象是哪个
Java8中判断一个对象不为空存在一个类对象是哪个? 在Java 8中,你可以使用java.util.Optional类来处理可能为空的对象。Optional类可以帮助你优雅地处理空值情况,而不需要显式地进行空值检查。 这是一个简单的Optional示例: imp…...
项目:点餐系统
项目扩展: 1.订单操作 2.用户管理(临时用户生成用户注册与登录) 项目有可能涉及到的面试: 说说你的项目 为什么要做这个项目 服务器怎么搭建的 最初我自己写了一个简单的服务器,但是不太稳定,比较粗…...

ElasticSearch 5.6.3 自定义封装API接口
在实际业务中,查询 elasticsearch 时会遇到很多特殊查询,官方接口包有时不便利,特殊情况需要自定义接口,所以为了灵活使用、维护更新 编写了一套API接口,仅供学习使用 当前自定义API接口依赖 elasticsearch 5.6.3 版本…...

企业架构LNMP学习笔记51
企业案例使用: 主从模式: 缓存集群结构示意图: 去实现Redis的业务分离: 读的请求分配到从服务器上,写的请求分配到主服务器上。 Redis是没有中间件来进行分离的。 是通过业务代码直接来进行读写分离。 准备两台虚…...

rom修改----安卓系列机型如何内置app 如何选择so文件内置
系统内置app的需求 在与各工作室对接中操作单中,很多需要内置客户特定的有些app到系统里,这样方便客户刷入固件后直接调用。例如内置apk 去开机引导 去usb调试 默认开启usb安全设置等等。那么很多app内置有不同的反应。有的可以直接内置。有的需要加so…...
SpringMvc中的请求转发和重定向
之前的案例,我们发现request域中的值可以传到jsp页面中,也就是通过视图解析器跳转到视图的底层是请求转发。 如果我们跳转时不想使用视图解析器,可以使用原生HttpServletRequest进行请求转发或HttpServletResponse进行重定向: Req…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...

Python训练营-Day26-函数专题1:函数定义与参数
题目1:计算圆的面积 任务: 编写一个名为 calculate_circle_area 的函数,该函数接收圆的半径 radius 作为参数,并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求:函数接收一个位置参数 radi…...
Python爬虫实战:研究Restkit库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...

动态规划-1035.不相交的线-力扣(LeetCode)
一、题目解析 光看题目要求和例图,感觉这题好麻烦,直线不能相交啊,每个数字只属于一条连线啊等等,但我们结合题目所给的信息和例图的内容,这不就是最长公共子序列吗?,我们把最长公共子序列连线起…...

SQL注入篇-sqlmap的配置和使用
在之前的皮卡丘靶场第五期SQL注入的内容中我们谈到了sqlmap,但是由于很多朋友看不了解命令行格式,所以是纯手动获取数据库信息的 接下来我们就用sqlmap来进行皮卡丘靶场的sql注入学习,链接:https://wwhc.lanzoue.com/ifJY32ybh6vc…...