关于Excel自动换行,不会在西文单词中间换行的问题

news2025/7/15 3:38:34

工作上遇到了一个Excel中换行的问题,就是使用了Excel的默认自动换行后,如果一个单词很长,那么一般情况下是不会在单词中间换行的。在网上查了些资料,最终找到了一个不算太完美的方法。

结果

就是使用vba修改单元格里面的内容,根据单元格的宽度,以及字体的字号大小来粗略的估算一行可以放多少个字,然后插入硬换行符,vba里面是chr(10)+chr(13),大概的效果如下:
示例中的文字是:这里是 :big computerserviceimpl是我们有的时候也不没干鲜果品轜羁 and the services are all avalible
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以看到最终的效果确实是有些差强人意,明明感觉还是可以再放一个字符的
以下是例子中使用的代码:

'允许在西文单词中间换行,插入换行符
Sub formatCellString()
Dim c As Object
Dim fontName As String, fontSize As Integer, defaultFontSize As Integer
Dim str As String, count As Integer, limit As Integer

'在这里指定要格式化的是哪个单元格
Set c = Worksheets("Sheet2").Cells(1, 1)

fontName = c.font.Name
fontSize = c.font.SIZE
Dim resultString As String

'取Sheet1中第一行第1023列这个单元格的字体大小作为默认字体大小
'需要注意的是,如果实际业务中这个单元格的字体大小也被手动修改了的话,就需要寻找其他尚未被修改过字体及字号的单元格了
defaultFontSize = Worksheets("Sheet1").Cells(1, 1023).font.SIZE

'先获取单元格的宽度,单元格宽度是在字体默认大小下的
limit = WorksheetFunction.Ceiling(c.ColumnWidth * defaultFontSize / fontSize, 1)

'要进行格式化的字符串
str = c.Value
For i = 1 To Len(str)
    Dim cur As Integer, curStr As String
    
    '当前字符
    curStr = Mid(str, i, 1)
    
    '取得当前字符的长度,中文算2个,其他算1个
    If StrWithChinese(curStr) Then
        cur = 2
    Else
        cur = 1
    End If
    
    '这里直接写了个2是因为有时候中英文一起的计算当前行已有宽度时会有个正好相等的问题
    If (count + 2) >= limit Then
        
        '如果再加上当前字符后,当前行长度就等于单元格宽度了,则插入一个换行符
        resultString = resultString & Chr(10) & Chr(13) & curStr
        
        ' count从头开始统计
        count = 1
        'MsgBox ("restart count:" & count & " limit:" & limit & " cur:" & cur & " curStr:" & Mid(str, i, 1) & " result:" & resultString)
    Else
        
        '统计当前行字符数
        count = count + cur
        
        '拼接结果字符
        resultString = resultString & curStr
        'MsgBox ("continue count:" & count & " limit:" & limit & " cur:" & cur & " curStr:" & Mid(str, i, 1) & " result:" & resultString)
    End If
Next
'c.Value = resultString '实际使用时可取消该行注释
Worksheets("Sheet2").Cells(2, 1) = resultString '实际使用时可注释掉该行
End Sub

'判断是否包含中文字符
'源码引自:http://www.office-cn.net/excel-vba/981.html
Function StrWithChinese(StrChk As String) As Boolean
    StrChk = VBA.StrConv(StrChk, vbNarrow)
    StrWithChinese = IIf(Len(StrChk) < LenB(StrConv(StrChk, vbFromUnicode)), True, False)
End Function

当然了,这个代码是把sheet2里面A1的内容插入好换行符后写入到了A2单元格,只是为了好对比效果,如果是实际使用的话,可以根据注释修改一下最后的赋值语句即可。

好了,以下就是探索的过程了,如果只是使用的话,就可以不往下看了的。

探索一 单元格像素

首先,参考下面这篇博文
EXCEL的高度和宽度计算-文档值到像素:https://blog.csdn.net/qq_30436011/article/details/126462788

找到了文中引用的官方文档
SheetFormatProperties:https://learn.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.spreadsheet.sheetformatproperties?view=openxml-2.8.1

column:https://learn.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.spreadsheet.column?view=openxml-2.8.1

但是我电脑上的excel打开默认列宽是8.38,和这里给出的例子都不一样,就很痛苦

探索二 字符像素

又找到一篇,可以计算指定字体下,指定字符串的总长度,像素
https://oomake.com/question/1225304
文中提出以下代码来测量字符串像素宽度

'Option Explicit
'API Declares
Private Declare Function CreateDC Lib "gdi32.dll" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, lpInitData As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32.dll" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateFontIndirect Lib "gdi32.dll" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long
Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
Private Declare Function GetTextExtentPoint32 Lib "gdi32.dll" Alias "GetTextExtentPoint32A" (ByVal hdc As Long, ByVal lpsz As String, ByVal cbString As Long, lpSize As SIZE) As Long
Private Declare Function MulDiv Lib "kernel32.dll" (ByVal nNumber As Long, ByVal nNumerator As Long, ByVal nDenominator As Long) As Long
Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32.dll" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function DeleteDC Lib "gdi32.dll" (ByVal hdc As Long) As Long
Private Const LOGPIXELSY As Long = 90
Private Type LOGFONT
    lfHeight As Long
    lfWidth As Long
    lfEscapement As Long
    lfOrientation As Long
    lfWeight As Long
    lfItalic As Byte
    lfUnderline As Byte
    lfStrikeOut As Byte
    lfCharSet As Byte
    lfOutPrecision As Byte
    lfClipPrecision As Byte
    lfQuality As Byte
    lfPitchAndFamily As Byte
    lfFaceName As String * 32
End Type
Private Type SIZE
    cx As Long
    cy As Long
End Type
Public Function getLabelPixel(label As String, fontName As String, fontSize As Integer) As Integer
Dim font As New StdFont
  Dim sz As SIZE
  font.Name = fontName
  font.SIZE = fontSize
sz = GetLabelSize(label, font)
  getLabelPixel = sz.cx
End Function
Private Function GetLabelSize(text As String, font As StdFont) As SIZE
    Dim tempDC As Long
    Dim tempBMP As Long
    Dim f As Long
    Dim lf As LOGFONT
    Dim textSize As SIZE
' Create a device context and a bitmap that can be used to store a
    ' temporary font object
    tempDC = CreateDC("DISPLAY", vbNullString, vbNullString, ByVal 0)
    tempBMP = CreateCompatibleBitmap(tempDC, 1, 1)
' Assign the bitmap to the device context
    DeleteObject SelectObject(tempDC, tempBMP)
' Set up the LOGFONT structure and create the font
    lf.lfFaceName = font.Name & Chr$(0)
    lf.lfHeight = -MulDiv(font.SIZE, GetDeviceCaps(GetDC(0), 90), 72) 'LOGPIXELSY
    lf.lfItalic = font.Italic
    lf.lfStrikeOut = font.Strikethrough
    lf.lfUnderline = font.Underline
    If font.Bold Then lf.lfWeight = 800 Else lf.lfWeight = 400
    f = CreateFontIndirect(lf)
' Assign the font to the device context
    DeleteObject SelectObject(tempDC, f)
' Measure the text, and return it into the textSize SIZE structure
    GetTextExtentPoint32 tempDC, text, Len(text), textSize
' Clean up (very important to avoid memory leaks!)
    DeleteObject f
    DeleteObject tempBMP
    DeleteDC tempDC
  ' Return the measurements
    GetLabelSize = textSize
End Function

探索三

换个方向,从字符数量上来入手。这个也就是最终结果采用的思路了。
这里先说一下,每个电脑上的Excel都有一个默认字体和大小,以Excel2010为例,这个设置在:文件 -> 选项 -> 常规 ->新建工作簿时这个地方
在这里插入图片描述
接下来理思路:

  1. 参考探索一和探索二里面涉及的文章和文档来看,Excel里面的列宽度是指在默认字体及字号下的字符数。就是说如果我们打开一个Excel文件,不手动修改字体和字号的话,那么列宽是几,就可以显示出几个字符(一个汉字占两个字符)。

比如列宽是4时,可以显示4个数字或字母,或是两个中文汉字
在这里插入图片描述
再比如列宽是8,则可以显示8个数字或字母,或是4个中文
在这里插入图片描述

以上都是偶数,如果是奇数的话,中文可能就会需要换行显示了
在这里插入图片描述
这个字符数大致就是这样了。

  1. 来看一下字号,如果我们把字号扩大一倍,那么会怎么样呢,按理说应该是显示字符数会减少一半。以下以我的Excel默认字号是11为基础。
    比如列宽设置4,字号修改为22
    在这里插入图片描述
    实际测试发现字符宽度正好是4时,我们上面的推论就崩溃了。但是如果我们把宽度稍微拉大一点,比如4.38,就正好了
    在这里插入图片描述
    比如把列宽拉到8.38时
    在这里插入图片描述
    这样的话,也就基本符合我们(1)中的推论了。这个多出来的0.38应该就是探索一和探索二的文档中提到的margin padding以及gridline的宽度了吧。
  2. 总结:根据以上两点,我们发现 修改字号后可显示字符数 = 列宽 x 默认字号 / 修改后的字号,比如2中第二个图,可显示的字符数 = 4.38 * 11 / 22 = 2.19 大概就是2个字符。至于这个小数需要怎么取舍,我没有细致研究,有能力的大佬可以把优化后的代码发出来哈。以下是根据这个思路写出来的第一版代码
'判断是否包含中文字符
Function StrWithChinese(StrChk As String) As Boolean
    StrChk = VBA.StrConv(StrChk, vbNarrow)
    StrWithChinese = IIf(Len(StrChk) < LenB(StrConv(StrChk, vbFromUnicode)), True, False)
End Function

Sub formatA1()
Dim c As Object
Dim fontName As String, fontSize As Integer, defaultFontSize As Integer
Dim str As String, count As Integer, limit As Integer
Set c = Worksheets("Sheet2").Cells(2, 1)
fontName = c.font.Name
fontSize = c.font.SIZE
Dim resultString As String
'取第一行第1023列这个单元格的字体大小作为默认字体大小
defaultFontSize = Worksheets("Sheet2").Cells(1, 1023).font.SIZE
'MsgBox defaultFontSize
'先获取单元格的宽度,单元格宽度是在字体默认大小下的
limit = WorksheetFunction.Ceiling(c.ColumnWidth * defaultFontSize / fontSize, 1)
str = Worksheets("Sheet2").Cells(1, 1).Value
For i = 1 To Len(str)
    Dim cur As Integer, curStr As String
    '当前字符
    curStr = Mid(str, i, 1)
    '中文算2个,其他算1个
    If StrWithChinese(curStr) Then
        cur = 2
    Else
        cur = 1
    End If
    '这里直接写了个2是因为有时候中英文一起的计算当前行已有宽度时会有个正好相等的问题
    If (count + 2) >= limit Then
        '如果再加上当前字符后,当前行长度就等于单元格宽度了,则插入一个换行符
        resultString = resultString & Chr(10) & Chr(13) & curStr
        ' count从头开始统计
        count = 1
        'MsgBox ("restart count:" & count & " limit:" & limit & " cur:" & cur & " curStr:" & Mid(str, i, 1) & " result:" & resultString)
    Else
        '统计当前行字符数
        count = count + cur
        '拼接结果字符
        resultString = resultString & curStr
        'MsgBox ("continue count:" & count & " limit:" & limit & " cur:" & cur & " curStr:" & Mid(str, i, 1) & " result:" & resultString)
    End If
Next
c.Value = resultString
End Sub

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

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

相关文章

SpringBoot SpringBoot 开发实用篇 4 数据层解决方案 4.11 SpringBoot 整合 MongoDB

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇4 数据层解决方案4.11 SpringBoot 整合 MongoDB4.11.1 SpringBoot 整…

Redis 到底是单线程还是多线程呢?

前言 Redis是高性能分布式缓存常用中间件&#xff0c;我们经常说Redis是单线程的&#xff0c; 也有人说Redis在6.0版本采用了多线程&#xff0c;那么Redis到底是采用单线程呢&#xff1f;还是多线程&#xff1f; 通常说 Redis 是单线程&#xff0c;其实主要是指 Redis 对外提供…

CNCF基金会成员的分类

CNCF简介 2015年&#xff0c;谷歌与Linux基金会及众多行业合作伙伴一起建立了一个云原生计算基金会&#xff08;CNCF&#xff0c;Cloud Native Computing Foundation&#xff09;。CNCF旨在创建并推动一个新的计算范式&#xff0c;这个范式的目的是增强现代分布式系统&#xf…

dataset.py篇

dataset.py 目录&#xff1a; 前言观察数据书写代码函数解释 前言 在步骤中需要写自己的dataset类&#xff0c;并将label和image一一对应后返回。 观察数据 在书写dataset前最重要的就是要观察数据集&#xff0c;对数据集进行分析&#xff0c;比如了解图片大小&#xff0c…

maven基础入门

maven 1、maven简介 Apache Maven 是一个项目管理和构建工具&#xff0c;它基于项目对象模型(POM)的概念&#xff0c;通过一小段描述信息来管理项目的构建、报告和文档。官网 &#xff1a;http://maven.apache.org/什么是Maven&#xff1f;这里先引用知乎的一个回答 我先不说…

第五届“传智杯”全国大学生计算机大赛(练习赛) [传智杯 #5 练习赛] 复读

[传智杯 #5 练习赛] 复读 题目描述 给定若干个字符串&#xff0c;不定数量&#xff0c;每行一个。有些字符串可能出现了多次。如果读入一个字符串后&#xff0c;发现这个字符串以前被读入过&#xff0c;则这个字符串被称为前面相同的字符串的复读&#xff0c;这个字符串被称为…

Redis分布式锁剖析和几种客户端的实现

1. 背景 在传统的单体项目中&#xff0c;即部署到单个IIS上&#xff0c;针对并发问题&#xff0c;比如进销存中的出库和入库问题&#xff0c;多个人同时操作&#xff0c;属于一个IIS进程中多个线程并发操作的问题&#xff0c;这个时候可以引入线程锁lock/Monitor等&#xff0c;…

信息论随笔(三)交互信息量

之前讨论了一个事件的自信息量&#xff0c;但是实际情况下往往有多个事件发生&#xff0c;而且这些事件之间相互是有联系的。比如知道一个人踢足球&#xff0c;那么这个人很有可能会看世界杯。也就是说&#xff0c;我们可以通过一个事件获得另外一个事件的信息&#xff0c;或者…

解决Android Studio等开发软件出现更新TKK失败的两种方案

解决Android Studio等开发软件出现更新TKK失败的两种方案方案一 配置hosts1. 配置域名与IP2.扫描国内可用的IP方案二 替换翻译引擎百度翻译引擎在Android Studio等开发软件中利用Translation等翻译插件时&#xff0c;出现无法翻译的提示&#xff1a;更新TKK失败&#xff0c;请检…

数据结构之栈的实现及相关OJ题

&#x1f57a;作者启明星使 &#x1f383;专栏&#xff1a;《数据库》《C语言》 &#x1f3c7;分享一句话&#xff1a; 对的人会站在你的前途里 志同道合的人才看得懂同一片风景 大家一起加油&#x1f3c4;‍♂️&#x1f3c4;‍♂️&#x1f3c4;‍♂️ 希望得到大家的支持&am…

【毕业设计】新闻分类系统 - 深度学习 机器学习

文章目录0 前言1 简介2 参与及比较算法3 先说结论4 实现过程4.1 数据爬取4.2 数据预处理5 CNN文本分类6 最后0 前言 &#x1f525; Hi&#xff0c;大家好&#xff0c;这里是丹成学长的毕设系列文章&#xff01; &#x1f525; 对毕设有任何疑问都可以问学长哦! 这两年开始&a…

事件总线EventBus

事件总线是对发布-订阅模式的一种实现&#xff0c;是一种集中式事件处理机制&#xff0c;允许不同的组件之间进行彼此通信而又不需要相互依赖&#xff0c;达到一种解耦的目的。 什么是“总线”&#xff1a;一个集中式的事件处理机制。同时服务多个事件和多个观察者。相当于一个…

C#编程深入研究变量,类型和方法

编写正确的C#代码 简单的调试技术 变量的语法 声明类型和值 仅声明类型 访问修饰符 使用类型 通用内置类型 类型转换 推断式声明 自定义类型 类型综述 命名变量 变量的作用域 运算符 定义方法 指定参数 指定返回值 常见的Unity方法 Start方法 Update方法 …

金山云:基于 JuiceFS 的 Elasticsearch 温冷热数据管理实践

01 Elasticsearch 广泛使用带来的成本问题 Elasticsearch&#xff08;下文简称“ES”&#xff09;是一个分布式的搜索引擎&#xff0c;还可作为分布式数据库来使用&#xff0c;常用于日志处理、分析和搜索等场景&#xff1b;在运维排障层面&#xff0c;ES 组成的 ELK&#xff…

MMDetection3D库中的一些模块介绍

本文目前仅包含2个体素编码器、2个中间编码器、1个主干网络、1个颈部网络和1个检测头。如果有机会&#xff0c;会继续补充更多模型。 若发现内容有误&#xff0c;欢迎指出。 MMDetection3D的点云数据一般会经历如下步骤/模块&#xff1a; #mermaid-svg-q9Wy2NQvFHfuPWKs {font-…

骨传导原理是什么,佩戴骨传导耳机的过程中对于耳道有无损害

随着新时代的到来&#xff0c;我们周围的数码产品逐渐被新产物所替代&#xff0c;以往在耳机市面上&#xff0c;普遍都是入耳式耳机&#xff0c;但长时间佩戴这种耳机的话对于我们耳道来说是有着不可逆的伤害&#xff0c;而在近几年骨传导耳机的出现&#xff0c;打破了传统耳机…

18.Redis系列之AOF方式持久化

本文学习redis7两大持久化技术之一&#xff1a;AOF&#xff08;Append Only File&#xff09;日志追加方式持久化备份与还原&#xff0c;重写以及AOF方式的优缺点 1. AOF相关配置 首先我们先简单了解下Redis7中AOF相关配置 // 开启AOF方式持久化&#xff0c;默认no appendon…

基于真实场景解读 K8s Pod 的各种异常

在 K8s 中&#xff0c;Pod 作为工作负载的运行载体&#xff0c;是最为核心的一个资源对象。Pod 具有复杂的生命周期&#xff0c;在其生命周期的每一个阶段&#xff0c;可能发生多种不同的异常情况。K8s 作为一个复杂系统&#xff0c;异常诊断往往要求强大的知识和经验储备。结合…

骚戴独家笔试---SQL笔试

SQL笔试训练 查询结果去重 两种答案 查找某个年龄段的用户信息 查找除复旦大学的用户信息 三种答案 用where过滤空值练习 三种答案 查询NULL时&#xff0c;不能使用比较运算符(或者< >)&#xff0c;需要使用IS NULL运算符或者IS NOT NULL运算符。 操作符混合运用 我这里…

力扣 792. 匹配子序列的单词数

题目 给定字符串 s 和字符串数组 words, 返回 words[i] 中是s的子序列的单词个数 。 字符串的 子序列 是从原始字符串中生成的新字符串&#xff0c;可以从中删去一些字符(可以是none)&#xff0c;而不改变其余字符的相对顺序。 例如&#xff0c; “ace” 是 “abcde” 的子序…