学习Excel技术,关注微信公众号:

excelperfect

在很多情况下,我们都面临着需要确定字符串中第一个和最后一个数字的位置的问题,这可能是为了提取包围在这两个边界内的子字符串。然而,通常的公式都是针对所需提取的子字符串完全由数字组成,如果要提取的数字中有分隔符(例如电话号码)则无法使用。当然,可以先执行替换操作来去掉字符串中的分隔符,这可能会更复杂些。

本文仅涉及被提取的字符串内包含唯一的数字子字符串的情况。

我们以示例来讲解。先看一下要提取的数字中没有分隔符的情形,例如在单元格A1中的字符串如下:

Account No. 1234567890: requires attention

显然,我们要提取出1234567890。

下面是我们曾经使用的一个公式:

=-LOOKUP(1,-(MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&1/17)),ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))))&"**0"))

注意,必须在MID函数生成的值的末尾添加“**0”,以保证能够在任何情况下都得到正确的结果。例如,如果单元格A1中的字符串是:

Account No. 12-Jun: requires attention

使用没有添加“**0”的公式:

=-LOOKUP(1,-(MID(A2,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A2&1/17)),ROW(INDEX(A:A,1):INDEX(A:A,LEN(A2))))))

返回的结果不是12,而是43994,即日期2020-6-12对应的序数。连接字符串“** 0”后,确保类似于“12–Jun”的字符串变为“12–Jun**0”,这样Excel不会将它们认为数字。同样,这也适用于与科学记数法格式的数字相似的字符串。

当然,这样的字符串还必须具有使任何数字保持不变的特性。字符串“**0”等效于“E0”,即表示索引为0的科学计数法,与10 ^ 0一致,因此可保证以这种形式表示的任何数字都将是不变。可以在工作表中进行下列测试来验证:

=0+(147&"**0")

返回147。

=0+(147&"**2")

返回14700。

这种方式比“E0”更好,例如:

=-LOOKUP(1,-(MID(A2,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A2&1/17)),ROW(INDEX(A:A,1):INDEX(A:A,LEN(A2))))&"E0"))

得到的结果是36689,因为提取的子字符串为“12-JunE0”,Excel认为是日期2000-6-12。并且,“E”在不同的环境中可能有不同的解释。

好了!下面让我们看看一个相似的例子,但要提取的子字符串数字中包含有分隔符:

Account No. 1-234-5678-90: requiresattention

使用上面给出的公式:

=-LOOKUP(1,-(MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&1/17)),ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))))&"**0"))

返回1,而不是我们想要的1-234-5678-90。

正如上文提出的,先删除分隔符并不是一件简单的事:

=-LOOKUP(1,-(MID(SUBSTITUTE(A1,"-",""),MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&1/17)),ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))))&"**0"))

乍一看似乎可以,但返回的结果是1234567890。留给我们的是,如何在正确的位置重新插入分隔符?当然,如果所给字符串的格式是固定的,例如电话号码。然而,即便如此,使用多个REPLACE/SUBSTITUTE函数可能使公式更复杂。

本文寻找的是如何通过确定字符串中的第一个和最后一个数字来提取出子字符串的一种通用解决方案,而不管分隔符是什么、有多少,并且不需要执行替换操作。

在前面的一系列文章中,我们已经找到了一种非常合适的方法来确定字符串中第一个数字的位置,即MIN/FIND函数组合构造。然而,找到一种等效的用于确定字符串中最后一个数字的结构并不容易,能够实现这一点是关键。

对于MID函数的参数num_chars:

=MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&1/17)),[someconstruction])

假设希望避免[some construction]由两个单独的子句进行减法运算,其中一个是字符串内第一个数字的位置,另一个是最后一个数字的位置。我们首先查看一些确定字符串中最后一个数字的位置的公式结构,然后查看其中的哪一个(如果有的话)也可能有助于发现第一个数字的位置,这可能会很有用。下面是实现此目的的3种主要的公式结构:

公式1:

=MATCH(1,0/ISNUMBER(0+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1)))

公式2:

=LOOKUP(1,0/ISNUMBER(0+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1)),ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))))

公式3:

=MAX(IF(ISNUMBER(0+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1)),ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1)))))

其中,公式1和公式3是数组公式。

显然,最好的是公式1,因为它不需要重复ROW子句。但是,这样的构造还可以用于查找字符串中的第一个数字吗?如果不行,公式2可以吗?公式3呢?

我们先尝试减法运行,即使用确定最后一个数字位置的子句减去用于确定第一个数字位置的子句:

MATCH(1,0/ISNUMBER(0+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1)))-MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&1/17))

从而构成解决方案:

=MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&1/17)),1+MATCH(1,0/ISNUMBER(0+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1)))-MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&1/17)))

不错!但是,可以改进参数num_chars的构造吗?

一种方法是对上面给出的公式3:

=MAX(IF(ISNUMBER(0+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1)),ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1)))))

进行微小的调整。在2010年及以后的版本中,Excel提供了AGGREGATE函数,它不仅可使许多数组(CSE)结构转换为非CSE,而且还具有标准的CSE公式无法复制的其他优点。

与公式3等价的使用AGGREGATE函数的公式为:
=AGGREGATE(14,6,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1)))/ISNUMBER(0+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1)),1)

我们可以利用其来不只生成最大值或最小值,而是生成包含这两个值的数组。因此,构造公式:

=MMULT(AGGREGATE({14,15},6,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1)))/ISNUMBER(0+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1)),1),{1;-1})

转换为:

=MMULT({25,13},{1;-1})

其中的13和25分别代表字符串中第一个和最后一个数字的位置。

但是,其仍有一点缺陷,就是需要重复ROW结构。我们能否对此进行改进,找到不需要重复子句的公式构造?是的,可以使用:

MATCH("*",T(1/(1+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1))),{1,0})

这类似于AGGREGATE的结构,将一个数组传递给其参数,得到两个结果组成的数组。上面的公式转换为:

MATCH("*",T(1/(1+{"A";"c";"c";"o";"u";"n";"t";"";"N";"o";".";"";"1";"-";"2";"3";"4";"-";"5";"6";"7";"8";"-";"9";"0";"";"r";"e";"q";"u";"i";"r";"e";"s";"";"a";"t";"t";"e";"n";"t";"i";"o";"n"})),{1,0})

转换为:

MATCH("*",T(1/({#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;2;#VALUE!;3;4;5;#VALUE!;6;7;8;9;#VALUE!;10;1;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!})),{1,0})

转换为:

MATCH("*",T({#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;0.5;#VALUE!;0.333333333333333;0.25;0.2;#VALUE!;0.166666666666667;0.142857142857143;0.125;0.111111111111111;#VALUE!;0.1;1;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!}),{1,0})

转换为:

MATCH("*",{#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;"";#VALUE!;"";"";"";#VALUE!;"";"";"";"";#VALUE!;"";"";#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!;#VALUE!},{1,0})

可以看出,不是错误值的就是数字值。指定参数match_type的值为1将为提供数组中最后一个非#VALUE!的位置;为0将提供第一个非#VALUE!的位置。这样,上面公式转换成:

{25,13}

现在,可以将此数组传递给MMULT函数,以最终得出MID函数的参数num_chars参数的值。最终的公式为:

=MID(A1,MIN(FIND({1,2,3,4,5,6,7,8,9,0},A1&1/17)),1+MMULT(MATCH("*",T(1/(1+MID(A1,ROW(INDEX(A:A,1):INDEX(A:A,LEN(A1))),1))),{1,0}),{1;-1}))

注:本技巧整理自excelxor.com,有兴趣的朋友对照原文研读,收获更丰。

java替换最后一个字符_Excel公式技巧23: 同时定位字符串中的第一个和最后一个数字...相关推荐

  1. excel取末尾数字_Excel公式技巧11: 从字符串中提取数字——数字位于字符串末尾...

    excelperfect 上篇文章讲解了提取位于字符串开头的数字的公式技术,本文研究从字符串开头提取数字的技术: 1. 这些数字是连续的 2. 这些连续的数字位于字符串的末尾 3. 想要的结果是将这些 ...

  2. 包含数字和指定字符的正则表达式_Excel公式练习39: 求字符串中的数字组成的数能够被指定数整除的数的个数...

    学习Excel技术,关注微信公众号: excelperfect 导语:继续研究来自于excelxor.com的案例.这个案例比较复杂,需要仔细研究. 本次的练习是:在单元格A1中输入一个任意长度的字母 ...

  3. linux删除最后一个字符串,Bash删除字符串中的第一个和最后一个字符

    问题描述 我有一个这样的字符串: |abcdefg| 我想要得到一个新的字符串(如string2)与原始字符串调用没有两个|在开始和结束时 所以我会有这个 abcdefg 在bash中可能吗? 最佳解 ...

  4. JAVA版本:给定一个字符串,返回字符串中小写英文字母的个数、数字个数以及其他字符的个数

    给定一个字符串,返回字符串中小写英文字母的个数.数字个数以及其他字符的个数 方法分析:使用replaceAll()方法,逐一删除字符串中的相关数据,类型个数=原长度-新长度 public static ...

  5. Java黑皮书课后题第6章:*6.20(计算一个字符串中字母的个数)编写一个方法,使用下面的方法体计算字符串中的字母个数。编写一个测试程序,提示用户输入字符串,然后显示字符串中的字母个数

    6.20(计算一个字符串中字母的个数)编写一个方法,使用下面的方法体计算字符串中的字母个数.编写一个测试程序,提示用户输入字符串,然后显示字符串中的字母个数 题目 题目描述 破题 代码 运行示例 题目 ...

  6. java 字符串编程题_Java编程题——在一个字符串中查找第一个非重复的字符

    编写一个Java程序来查找一个字符串中第一个非重复的字符,这是在编程测试中很常见的一个问题,因为字符串处理在程序员面试中是一个普遍的话题.面试前最好是准备好一些熟知的编程问题,例如使用递归反转字符串, ...

  7. c语言字符串去除第一个和最后一个_387. 字符串中的第一个唯一字符

    387. 字符串中的第一个唯一字符 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引.如果不存在,则返回 -1. 示例: s = "leetcode" 返回 0s = & ...

  8. LeetCode刷题第8天字符串系列之《378字符串中的第一个唯一字符》

    LeetCode 378字符串中的第一个唯一字符 题目描述 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引.如果不存在,则返回 -1. 提示:你可以假定该字符串只包含小写字母. 示例 输入 ...

  9. java用正则表达式判断字符串中是否仅包含英文字母、数字和汉字_灵思致远Leansmall的博客-CSDN博客_java判断字符串只包含数字字母

    import java.util.regex.Matcher; import java.util.regex.Pattern;public class StrValidate {// 纯数字priva ...

最新文章

  1. Spring Data JPA 五分钟快速入门和实践
  2. 微生物组入门必读+宏基因组实操课程=新老司机赶快上车
  3. python自学免费课堂-python自学——文件打开
  4. 【UDP协议头解析】
  5. 2020-2021家居行业年度盘点与趋势洞察
  6. (王道408考研数据结构)第二章线性表-第一节:线性表的定义和基本操作
  7. Simpleperf: 一款能在Android 做 Native Profiling 的工具
  8. 轮到苹果追赶国产厂商了?苹果新专利曝光iPhone将使用屏幕指纹解锁
  9. 获取指定路径下所有PDF文件的总页数
  10. 难道千元机的品质真的不如旗舰机吗?
  11. CS229学习笔记(3)逻辑回归(Logistic Regression)
  12. Sixpack —— 支持多语言的 A/B 测试框架
  13. 某文件在桌面上,命令窗口中找不到,因为桌面是两个目录合成的
  14. resnet34\resnet101网络结构图
  15. linux纯终端下中文输入,Ubuntu 14.04 终端模式下中文输入 听歌
  16. 凯撒密码加密算法python_密码学初探:隐藏信息的艺术——区块链技术引卷之十一...
  17. 第4关国际标准书号校验python 头歌
  18. 前端切图仔,常用的21个字符串方法
  19. 脱口而出的 “ 感谢的语言 ”
  20. 安卓、苹果怎么多开微信?微信多开软件

热门文章

  1. python求平方根的小数_python中的数字和数学运算
  2. CSDN中最全python字典和实例,让你轻松掌握
  3. Java基础05 break和continue比较区别
  4. java log4j记录_JAVA中使用LOG4J记录日志
  5. 怎么把外部参照合并到图纸_CAD图纸中插入的参照底图如何使用
  6. php 字符串转 buffer,这个字符串转换类用处大吗?-PHP教程,PHP应用
  7. java对接支付宝微信银联_JavaWEB后端支付银联,支付宝,微信对接
  8. php最复杂,php – 什么方法最好构建这个复杂的图
  9. php mysql encode_PHP json_encode mysql结果
  10. 基于php校园失物招领,校园失物招领系统的设计.doc