Unity功能模块一对话系统(4)实现个性文本标签

news2025/2/6 0:48:54

本期我们将了解如何在TMPro中自定义我们的标签样式,并实现两种有趣的效果。

一.需求描述

1.定义<float>格式的标签,实现标签处延迟打印功能

2.定义<r=" "></r>格式的标签,实现标签区间内文本片段的注释显示功能

3.补充文本多种打印样式功能。

二.自定义标签样式

首先我们需要借助预处理器来读取到我们的目标格式的标签,并记录标签内的相关信息

基本思路:通过ITextPreprocessor接口实现预处理器的预加工函数PreprocessText(),读取到文本中的自定义标签格式并记录标签内信息。

1.实现接口方法

 public class AdvancedTextPreprocessor : ITextPreprocessor
 {
     public string PreprocessText(string text){}
 }

2.提取标签

(1)使用正则表达式来匹配<>的类html格式。

  public string PreprocessText(string text)
  {
    string processingText = text;
    string pattern = "<.*?>";//定义一个正则表达式 "<.*>" 用于匹配所有以 < 开头、> 结尾的字符串。贪婪模式,即它会匹配最远的 >
    Match match = Regex.Match(processingText, pattern);//首次匹配,查找所有富文本标签

    while (match.Success) //尝试匹配富文本标签
    {
        match = Regex.Match(processingText, pattern);//继续匹配,查找下一个标签
    }

    processingText = text;
    return processingText;
}

    //正则表达式概念
    // . 代表任意字符
    //*代表前一个字符出现0次或多次
    //+代表前一个字符出现1次或多次
    //?代表前一个字符出现0次或1次

这里我们定义了<.*?>这种文本模式,下方代码将在用户文本中查找符合模式的文本片段match。

 Match match = Regex.Match(processingText, pattern);//按照pattern模式来匹配用户文本中符合格式的文本(含<>)

3.记录标签内信息

下面我们需要记录下我们的自定义标签内的信息。

1.定义存储结构

/// <summary>
/// 打印延迟字典【读取标签<float>,遇到将延迟float秒后打印后面内容】
/// </summary>
public Dictionary<int, float> IntervalDictionary = new Dictionary<int, float>();//自定义打印标签字典

/// <summary>
/// 注释标签列表
/// </summary>
public List<RubyData> rubyList = new List<RubyData>();

这里我使用字典存储延迟标签信息,将延迟标签的位置偏移作为键,延迟长度作为值。

使用列表来存储注释数据结构。成员是Rubydata类的实例。

Rubydata类中定义了3种属性:注释自身在文本中的起止位置偏移startIndex和终止位置偏移endIndex,以及注释内容contnet。

RubyData类如下

 /// <summary>
 /// 注释数据
 /// </summary>
 public class RubyData
 {
     public RubyData(int _startIndex, string _content)
     {
         startIndex = _startIndex;
         rubyContent = _content;
     }

     public int startIndex { get; }
     public string rubyContent { get; }
     public int endIndex { get; set; }

 }

2.匹配<>标签内的文本信息

下方代码功能是去除match文本中包含的<>字符,得到标签内的信息label。

 string label = match.Value.Substring(1, match.Length - 2);

3.标签内信息的存储逻辑

(1)读取<float>格式标签内容
  //自定义延迟打印标签【规定<float>】并记录在打印间隔标签字典中
  if (float.TryParse(label, out float result))
      IntervalDictionary[match.Index - 1] = result;

此处由于标签内部就是一个float类型的数据,所以我们可以直接就爱那个标签记录在我们的打印间隔标签字典中

(2)读取<r=" "></r>格式标签内容
  //自定义注释标签【规定<r="">】录入注释列表
  //注释标签开启
   if (Regex.IsMatch(label, "^r=.+")) //^:表示字符串的开头。这个符号确保匹配的字符串必须从开头开始
      rubyList.Add(new RubyData(match.Index, label.Substring(2)));

  //注释标签终止
  else if (Regex.IsMatch(label, "/r"))
  {
      if (rubyList.Count > 0)
          rubyList[rubyList.Count - 1].endIndex = match.Index - 1;
  }

4.去除标签文本

由于我们在用户文本中含有<>的类html标签,但是最终是不需要显示的,所以我们还需要在用户文本的基础上去除我们的标签(替换为空字符串),才能得到最终的渲染文本。

 pattern = @"(<(\d+)(\.\d+)?>)|(</r>)|(<r=.*?>)";//使用 @ 前缀可以避免在字符串中使用转义字符
                                                    
 //将处理文本中符合pattern规则的字符串 替换为空字符串""
 processingText = Regex.Replace(processingText, pattern, "");

完整源码见后文。


三.实现自定义文本效果

1.延迟打印功能

现在我们已经可以存储文本中的自定义标签内的信息,我们现在来实现一下文本的自定义效果。

我们前面已经实现了打字机的效果,实际上的延时打印功能,就是在打字函数的携程循环中等待的迭代函数。

       if (selfPreprocessor.IntervalDictionary.TryGetValue(typingIndex, out float result))
           yield return new WaitForSecondsRealtime(result);
       else
           yield return new WaitForSecondsRealtime(defalutInterval);

上句代码用来判断文本中当前打印位置处会否是延迟标签所在位置。如果恰好是字典中延迟标签的位置,则返回字典中的的当前位置键对应的float值作为输入执行携程延迟函数。否则按照默认间隔执行打印延迟。

2.注释功能

我们具体会用到两个方法。

(1)生成并设置注释

void SetRubyText(RubyData data)
{
    GameObject ruby = Instantiate(Resources.Load<GameObject>("RubyText"), transform);
    ruby.GetComponent<TextMeshProUGUI>().SetText(data.rubyContent);
    ruby.GetComponent<TextMeshProUGUI>().color = textInfo.characterInfo[data.startIndex].color;
    ruby.transform.localPosition = (textInfo.characterInfo[data.startIndex].topLeft + textInfo.characterInfo[data.endIndex].topRight) / 2 - new Vector3(0, 10, 0);
}

这里我们传入一个Rubydata实例,设置预制件文本,颜色及位置。

(2)判断当前位置是否是注释的起始位

    /// <summary>
    /// 读取一个位置是否就是Ruby起始位
    /// </summary>
    /// <param name="index"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public bool TryGetRubyText(int index, out RubyData data)
    {
        data = new RubyData(0, "");
        foreach (RubyData item in rubyList)
        {

            if (item.startIndex == index)
            {
                data = item;
                return true;
            }
        }
        return false;
    }
}

每打印到一个位置,我们都需要判断当前位置是否是注释标签的起始位。如果是,将调用生成注释预制件的函数。


四.改进文本显示逻辑

现在我们去AdvancedText类中改进一下前面实现的文本显示逻辑。

增添字段
    Coroutine typingCor;//存储打字携程,易于中断

    Action OnFinish; //文本打印结束的回调委托

这里的携程字段使用来记录我们的打字机携程的,实际情况中我们会遇到 打断正在打印中文本 的需求。存储到一个携程变量中将易于管理。

增添枚举

我们使用一个枚举来决定文本以什么形式显示。(见下方)

public enum E_DisplayType 
{
    Defalut,Fading,Typing
}

Defalut模式:文本采用 整体直接显示。

Fading模式:文本采用 整体淡入显示。

Typing模式:文本采用 打字机淡入效果显示。

我们现在实现一下各种打印样式的函数。

Defalut模式显示方法
  /// <summary>
  /// 文本整体直接显示
  /// </summary>
  void DefalutDisplay(Action action = null)
  {
      for (int i = 0; i < m_characterCount; i++)
          SetSingleCharacterAlpha(i, 255);
      action?.Invoke();
  }
Fading模式显示方法
 /// <summary>
 /// 文本整体淡入显示
 /// </summary>
 void FadingDisplay(float fadeDuration,Action action=null)
 {
     for (int i = 0; i < m_characterCount; i++)
         StartCoroutine(FadeInCharacter(i, fadeDuration));
     action?.Invoke();
 }
Typing模式显示方法
 /// <summary>
 /// 文本打字机显示
 /// </summary>
 /// <returns></returns>
 IEnumerator TypingDisplay(float fadeDuration,Action action = null)
 {
     ForceMeshUpdate();
     for (int i = 0; i < m_characterCount; i++)
     {
         SetSingleCharacterAlpha(i, 0);
     }
     typingIndex = 0;
     while (typingIndex < m_characterCount)
     {

         //SetSingleCharacterAlpha(typingIndex,255);   //无淡入打字机效果
         StartCoroutine(FadeInCharacter(typingIndex, fadeDuration)); //淡入打字机效果

         if (selfPreprocessor.IntervalDictionary.TryGetValue(typingIndex, out float result))
             yield return new WaitForSecondsRealtime(result);
         else
             yield return new WaitForSecondsRealtime(defalutInterval);

         typingIndex++;
     }
     action?.Invoke();
 }
文本显示方法

我们还需要一个函数作为暴露给外部的应用接口,客户端可以选择不同的文本显示样式。

  public IEnumerator ShowText(string content, E_DisplayType displayType, float duration)
  {
      if (typingCor != null)
      {
          StopCoroutine(typingCor);
      }
      typingCor = null;
      SetText(content);
      yield return null;
      TextDisAppear();
      switch (displayType)
      {
          case E_DisplayType.Defalut:
              DefalutDisplay();
              SetAllRubyTexts();
              break;
          case E_DisplayType.Fading:
              FadingDisplay(duration);
              SetAllRubyTexts();
              break;
          case E_DisplayType.Typing:
              typingCor = StartCoroutine(TypingDisplay(duration));
              break;
          default:
              break;
      }
  }

五.功能测试

在测试脚本中我们调用AdvancedText实例的携程来显示文本。

 StartCoroutine(advancedText.ShowText(content,displayType,duration));

编辑器内选择打印样式。

运行效果

这里我是做了一个按键输入功能,通过按键显示并开始打印文本,但调用文本打印的逻辑是一致的。如果大家对UI动效有有兴趣的话我后面可以出一期关于UI的代码框架及动效功能的解决方案。


六.完整源码

AdvancedTextPreprocessor类  

using System.Collections.Generic;
using System.Text.RegularExpressions;
using TMPro;

namespace DialogueDemo
{
    public class AdvancedTextPreprocessor : ITextPreprocessor
    {
        /// <summary>
        /// 打印延迟字典【读取标签<float>,遇到将延迟float秒后打印后面内容】
        /// </summary>
        public Dictionary<int, float> IntervalDictionary = new Dictionary<int, float>();//自定义打印标签字典

        public List<RubyData> rubyList = new List<RubyData>();
        public string PreprocessText(string text)
        {
            IntervalDictionary.Clear();
            string processingText = text;
            string pattern = "<.*?>";//定义一个正则表达式 "<.*>" 用于匹配所有以 < 开头、> 结尾的字符串。贪婪模式,即它会匹配最远的 >
            Match match = Regex.Match(processingText, pattern);//首次匹配,查找所有富文本标签

            while (match.Success) //尝试匹配富文本标签
            {
                string label = match.Value.Substring(1, match.Length - 2);
                //自定义延迟打印标签【规定<float>】并记录在打印间隔标签字典中
                if (float.TryParse(label, out float result))
                    IntervalDictionary[match.Index - 1] = result;
                //自定义注释标签【规定<r="">】录入注释列表
                //注释标签开启
                else if (Regex.IsMatch(label, "^r=.+")) //^:表示字符串的开头。这个符号确保匹配的字符串必须从开头开始
                    rubyList.Add(new RubyData(match.Index, label.Substring(2)));

                //注释标签终止
                else if (Regex.IsMatch(label, "/r"))
                {
                    if (rubyList.Count > 0)
                        rubyList[rubyList.Count - 1].endIndex = match.Index - 1;
                }

                processingText = processingText.Remove(match.Index, match.Length);//读取此打印间隔标签后,删除此标签
                if (Regex.IsMatch(label, "^sprite.+"))  //如果标签格式是精灵,需要一个占位符
                    processingText.Insert(match.Index, "*");

                match = Regex.Match(processingText, pattern);//继续匹配,查找下一个标签
            }

            processingText = text;
            //正则表达式概念
            // . 代表任意字符
            //*代表前一个字符出现0次或多次
            //+代表前一个字符出现1次或多次
            //?代表前一个字符出现0次或1次

            pattern = @"(<(\d+)(\.\d+)?>)|(</r>)|(<r=.*?>)";//使用 @ 前缀可以避免在字符串中使用转义字符
                                                            //简单解释:本句代码实现了读取<>中的整数或小数的功能
            /* (\d +):
            \d + 是一个数字匹配模式,它匹配一个或多个数字字符。+表示前面的模式(数字)可以匹配一个或多个字符。
            () 是捕获组的标记,这样 \d + 匹配到的数字部分就会被捕获到组中,可以在后续处理中使用。

            (\.\d +)?:
            \. 匹配一个字面上的点(.)。点号是一个元字符,在正则中表示任意字符,但在这里需要加 \ 进行转义,表示字面上的点号。
            \d + 匹配一个或多个数字,表示小数点后面的部分。
            () ? 表示这个捕获组是可选的,即小数部分不是必需的。如果没有小数部分,这一部分会被忽略。*/

            //将处理文本中符合pattern规则的字符串 替换为 后面的字符串
            processingText = Regex.Replace(processingText, pattern, "");

            return processingText;
        }

        /// <summary>
        /// 读取一个位置是否就是Ruby起始位
        /// </summary>
        /// <param name="index"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool TryGetRubyText(int index, out RubyData data)
        {

            data = new RubyData(0, "");
            foreach (RubyData item in rubyList)
            {

                if (item.startIndex == index)
                {
                    data = item;
                    return true;
                }
            }
            return false;
        }
    }

    /// <summary>
    /// 注释数据
    /// </summary>
    public class RubyData
    {
        public RubyData(int _startIndex, string _content)
        {
            startIndex = _startIndex;
            rubyContent = _content;
        }

        public int startIndex { get; }
        public string rubyContent { get; }
        public int endIndex { get; set; }

    }
}

AdvancedText类

using System;
using System.Collections;
using TMPro;
using UnityEngine;

namespace DialogueDemo
{
    public class AdvancedText : TextMeshProUGUI
    {
        int typingIndex;
        float defalutInterval = 0.08f;
        Coroutine typingCor;//存储打字携程,易于中断

        Action OnFinish;
        AdvancedTextPreprocessor selfPreprocessor => (AdvancedTextPreprocessor)textPreprocessor;

        private void Init()
        {
            SetText("");
            ClearRubyText();
        }

        public AdvancedText()
        {
            textPreprocessor = new AdvancedTextPreprocessor();
        }
        public void TextDisAppear()
        {
            for (int i = 0; i < m_characterCount; i++)
                SetSingleCharacterAlpha(i, 0);
        }

        public IEnumerator ShowText(string content, E_DisplayType displayType, float duration)
        {
            if (typingCor != null)
            {
                StopCoroutine(typingCor);
            }
            typingCor = null;
            SetText(content);
            yield return null;
            TextDisAppear();
            switch (displayType)
            {
                case E_DisplayType.Defalut:
                    DefalutDisplay();
                    SetAllRubyTexts();
                    break;
                case E_DisplayType.Fading:
                    FadingDisplay(duration);
                    SetAllRubyTexts();
                    break;
                case E_DisplayType.Typing:
                    typingCor = StartCoroutine(TypingDisplay(duration));
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 直接显示
        /// </summary>
        void DefalutDisplay(Action action = null)
        {
            for (int i = 0; i < m_characterCount; i++)
                SetSingleCharacterAlpha(i, 255);
            action?.Invoke();
        }

        /// <summary>
        /// 整体淡入
        /// </summary>
        void FadingDisplay(float fadeDuration,Action action=null)
        {
            for (int i = 0; i < m_characterCount; i++)
                StartCoroutine(FadeInCharacter(i, fadeDuration));
            action?.Invoke();
        }

        /// <summary>
        /// 打字机显示
        /// </summary>
        /// <returns></returns>
        IEnumerator TypingDisplay(float fadeDuration,Action action = null)
        {
            ForceMeshUpdate();
            for (int i = 0; i < m_characterCount; i++)
            {
                SetSingleCharacterAlpha(i, 0);
            }
            typingIndex = 0;
            while (typingIndex < m_characterCount)
            {

                //SetSingleCharacterAlpha(typingIndex,255);   //无淡入打字机效果
                StartCoroutine(FadeInCharacter(typingIndex, fadeDuration)); //淡入打字机效果

                if (selfPreprocessor.IntervalDictionary.TryGetValue(typingIndex, out float result))
                    yield return new WaitForSecondsRealtime(result);
                else
                    yield return new WaitForSecondsRealtime(defalutInterval);

                typingIndex++;
            }
            action?.Invoke();
        }

        /// <summary>
        /// 设置单字符的透明度(每个字符都是由网格(含4个顶点)渲染)
        /// </summary>
        /// <param name="index"></param>
        /// <param name="newAlpha">newalpha范围为0~255</param>
        void SetSingleCharacterAlpha(int index, byte newAlpha)
        {
            TMP_CharacterInfo character = textInfo.characterInfo[index];//获取文本内容索引下的单个字符
            if (!character.isVisible)
                return;
            int matIndex = character.materialReferenceIndex;//获取字符材质索引
            int vertexIndex = character.vertexIndex;//获取字符顶点索引
            for (int i = 0; i < 4; i++)
            {
                textInfo.meshInfo[matIndex].colors32[vertexIndex + i].a = newAlpha;
            }
            UpdateVertexData();//更新顶点数据
        }

        /// <summary>
        /// 单字符淡入
        /// </summary>
        /// <param name="index"></param>
        /// <param name="duration"></param>
        /// <returns></returns>
        IEnumerator FadeInCharacter(int index, float duration)
        {
            //如果找到Ruby起始位,设置Ruby预制件
            Debug.Log(selfPreprocessor.TryGetRubyText(index, out var data1));

            if (selfPreprocessor.TryGetRubyText(index, out RubyData data))
                SetRubyText(data);

            if (duration <= 0)
                SetSingleCharacterAlpha(index, 255);
            else
            {
                float timer = 0;
                while (timer < duration)
                {
                    timer = Mathf.Min(duration, timer + Time.unscaledDeltaTime);
                    SetSingleCharacterAlpha(index, (byte)(255 * (timer / duration)));
                    yield return null;
                }
            }
        }

        void SetRubyText(RubyData data)
        {
            GameObject ruby = Instantiate(Resources.Load<GameObject>("RubyText"), transform);
            ruby.GetComponent<TextMeshProUGUI>().SetText(data.rubyContent);
            ruby.GetComponent<TextMeshProUGUI>().color = textInfo.characterInfo[data.startIndex].color;
            ruby.transform.localPosition = (textInfo.characterInfo[data.startIndex].topLeft + textInfo.characterInfo[data.endIndex].topRight) / 2 - new Vector3(0, 10, 0);
        }

        /// <summary>
        /// 清除当前的所有注释
        /// </summary>
        void ClearRubyText()
        {
            foreach (var item in GetComponentsInChildren<TextMeshProUGUI>())
            {
                if (item != this)
                    Destroy(item.gameObject);
            }
        }

        /// <summary>
        /// 用于跳过对话直接显示所有注释
        /// </summary>
        void SetAllRubyTexts()
        {
            foreach (var item in selfPreprocessor.rubyList)
            {
                SetRubyText(item);
            }
        }
    }
}

七.尾声

       在 Unity 的 TextMeshPro中,文本标签(如 <color=red>...</color>)的处理方式不同于我们在自定义 AdvancedTextPreprocessor 类中的实现。TextMeshPro 之所以能正确处理 <color=red> </color> 等标签,原因在于它内部已经预先实现了一个功能强大的解析器,用于识别和处理各种富文本标签。TMP处理这些标签的方法是通过其 TextParser 类内部的规则和机制。具体的实现位于 TextMeshPro 的源码中,这些规则和方法是在 TextMeshPro 的组件中预定义的。当你将含有富文本标签的字符串传递给 TMP_Text 组件时,TextMeshPro 会自动解析这些标签并应用对应的样式。这与 AdvancedTextPreprocessor 类不同,后者是我们自己实现的自定义处理器,它仅仅处理我们通过正则表达式解析并手动处理的标签(例如延迟打印标签、注释标签等),并不会干预 TextMeshPro 内部已经定义的标准标签处理。

本篇完

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Llama 3 预训练(二)

目录 3. 预训练 3.1 预训练数据 3.1.1 网络数据筛选 PII 和安全过滤 文本提取与清理 去重&#xff08;De-duplication&#xff09; 启发式过滤&#xff08;Heuristic Filtering&#xff09; 基于模型的质量过滤 代码和数学推理数据处理 多语言数据处理 3.1.2 确定数…

电路元件与电路基本定理

电流、电压和电功率 电流 1 定义&#xff1a; 带电质点的有序运动形成电流 。 单位时间内通过导体横截面的电量定义为电流强度&#xff0c; 简称电流&#xff0c;用符号 i 表示&#xff0c;其数学表达式为&#xff1a;&#xff08;i单位&#xff1a;安培&#xff08;A&#x…

低代码开源项目Joget的研究——基本概念和Joget7社区版应用

大纲 1. 基本概念1.1 Form1.1.1 Form1.1.1.1 概述1.1.1.2 主要特点和用途1.1.1.3 创建和使用 Form1.1.1.4 示例 1.1.2 Section1.1.2.1 概述1.1.2.2 主要特点和用途1.1.2.3 示例 1.1.3 Column1.1.4 Field1.1.5 示例 1.2 Datalist1.2.1 Datalist1.2.1.1 主要特点和用途1.2.1.2 创…

【二叉树遍历 Java版】二叉树的前中后序遍历and层次遍历

二叉树的前中后序遍历and层次遍历 深度优先遍历题目链接递归前序遍历中序遍历后序遍历 迭代前序遍历后序遍历中序遍历 统一迭代前序遍历后序遍历中序遍历 广度优先遍历102. 二叉树的层序遍历107. 二叉树的层序遍历 II637. 二叉树的层平均值199. 二叉树的右视图 深度优先遍历 深…

【Sentinel】初识Sentinel

目录 1.1.雪崩问题及解决方案 1.1.1.雪崩问题 1.1.2.超时处理 1.1.3.仓壁模式 1.1.4.断路器 1.1.5.限流 1.1.6.总结 1.2.服务保护技术对比 1.3.Sentinel介绍和安装 1.3.1.初识Sentinel 1.3.2.安装Sentinel 1.4.微服务整合Sentinel 1.1.雪崩问题及解决方案 1.1.1.…

Apriori关联规则算法 HNUST【数据分析技术】(2025)

1.理论知识 Apriori是一种常用的数据关联规则挖掘方法&#xff0c;它可以用来找出数据集中频繁出现的数据集合。该算法第一次实现在大数据集上的可行的关联规则提取&#xff0c;其核心思想是通过连接产生候选项及其支持度&#xff0c;然后通过剪枝生成频繁项集。 Apriori算法的…

如何让Tplink路由器自身的IP网段 与交换机和电脑的IP网段 保持一致?

问题分析&#xff1a; 正常情况下&#xff0c;我的需求是&#xff1a;电脑又能上网&#xff0c;又需要与路由器处于同一局域网下&#xff08;串流Pico4 VR眼镜&#xff09;&#xff0c;所以&#xff0c;我是这么连接 交换机、路由器、电脑 的&#xff1a; 此时&#xff0c;登录…

系统思考—冰山模型

“卓越不是因机遇而生&#xff0c;而是智慧的选择与用心的承诺。”—— 亚里士多德 卓越&#xff0c;从来不是一次性行为&#xff0c;而是一种习惯。正如我们在日常辅导中常提醒自己&#xff1a;行为的背后&#xff0c;隐藏着选择的逻辑&#xff0c;而选择的根源&#xff0c;源…

TP5 动态渲染多个Layui表格并批量打印所有表格

记录&#xff1a; TP5 动态渲染多个Layui表格每个表格设置有2行表头&#xff0c;并且第一行表头在页面完成后动态渲染显示内容每个表格下面显示统计信息可点击字段排序一次打印页面上的所有表格打印页面上多个table时,让每个table单独一页 后端代码示例&#xff1a; /*** Nod…

【笔记】linux虚拟机与windows的文件共享之Samba服务基本配置

做完之后的总结写在最前面便于复习&#xff1a; 虚拟机上要共享的资源通过samba的操作 允许window通过网络去访问其共享资源 防止以后看不懂放在最前面 &#xff08;一&#xff09;虚拟机操作部分 下载 samba smbclient samba-common 在根目录/新建一个samba专用文件夹&…

PyTorch Instance Normalization介绍

Instance Normalization(实例归一化) 是一种标准化技术,与 Batch Normalization 类似,但它对每个样本独立地对每个通道进行归一化,而不依赖于小批量数据的统计信息。这使得它非常适合小批量训练任务以及图像生成任务(如风格迁移)。 Instance Normalization 的原理 对每…

攻防世界web新手第五题supersqli

这是题目&#xff0c;题目看起来像是sql注入的题&#xff0c;先试一下最常规的&#xff0c;输入1&#xff0c;回显正常 输入1‘&#xff0c;显示错误 尝试加上注释符号#或者–或者%23&#xff08;注释掉后面语句&#xff0c;使1后面的单引号与前面的单引号成功匹配就不会报错…

机器视觉中的单线程、多线程与跨线程:原理与应用解析

在机器视觉应用中&#xff0c;程序的运行效率直接影响到系统的实时性和稳定性。随着任务复杂度的提高&#xff0c;单线程处理往往无法满足高性能需求&#xff0c;多线程技术因此被广泛应用。此外&#xff0c;跨线程操作&#xff08;如在多线程中更新界面或共享资源&#xff09;…

JAVA学习笔记第二阶段开始 Day11 五种机制---机制1:泛型机制

JAVA基础进阶版链接 https://pdai.tech/md/java/basic/java-basic-x-generic.html 五种机制 泛型机制 用处&#xff0c;提高类型安全性和代码重用 泛型在编写代码中使用【类型占位符】&#xff0c;而不是具体的类型&#xff0c;泛型是通过“类型擦除”来实现的类型安全性&…

ZLG嵌入式笔记 | 电源设计避坑(上)

产品上量后&#xff0c;通常都会有降成需求。多年来&#xff0c;接触过不少产品降成案例&#xff0c;在电源上下刀过猛&#xff0c;引发了产品偶发性问题&#xff0c;带来了很不好的负面影响。本文将对这些案例进行总结&#xff0c;提供电源设计参考&#xff0c;确保产品降成不…

全面了解 SQL Server:功能、优势与最佳实践

SQL Server 是微软公司推出的一款关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;广泛应用于企业级数据存储、数据分析、应用开发等领域。作为全球最受欢迎的数据库管理系统之一&#xff0c;SQL Server 提供了强大的功能和工具&#xff0c;支持从小型应用到大型…

WPF TextBox 输入限制 详解

总目录 前言 通常对于WPF输入框 输入的控制无非以下方式 1 直接禁止输入(包括粘贴) 不符合要求的字符 如只可输入数字的输入框&#xff0c;当你输入字母的时候是无法输入的 2 输入后&#xff0c;校验内容是否符合要求&#xff0c;然后提示错误&#xff0c;禁止提交信息 如只可…

从0入门自主空中机器人-4-【PX4与Gazebo入门】

前言: 从上一篇的文章 从0入门自主空中机器人-3-【环境与常用软件安装】 | MGodmonkeyの世界 中我们的机载电脑已经安装了系统和常用的软件&#xff0c;这一篇文章中我们入门一下无人机常用的开源飞控PX4&#xff0c;以及ROS中无人机的仿真 1. PX4的安装 1.1 PX4固件代码的下载…

Android笔记(四十一):TabLayout内的tab不滚动问题

背景 假设二级页面是上面图片的布局&#xff0c;当进来时TabLayout和ViewPager2绑定完就马上调setCustomItem&#xff0c;跳转到最后一个tab页面时&#xff0c;会发现tab不滚动&#xff0c;手动滑一下ViewPager2时才会滚动tab到正确的位置 原因分析 调用TabLayoutMediator.at…

Pandas04

Pandas01 Pandas02 Pandas03 文章目录 内容回顾1 数据的合并和变形1.1 df.append (了解)1.2 pd.concat1.3 merge 连接 类似于SQL的join1.4 join (了解) 2 变形2.1 转置2.2 透视表 3 MatPlotLib数据可视化3.1 MatPlotLib API 套路 &为什么要可视化3.2 单变量可视化3.3 双变量…