【问题标题】:excel functions find pattern of a string in a cellexcel函数在单元格中查找字符串的模式
【发布时间】:2015-02-05 21:32:43
【问题描述】:

我必须在一个单元格中找到报告中的个人 ID。太糟糕了,隐藏此 ID 的单元格中的字符串可以是任何东西,ID 可以在开头、结尾、任何地方,但它就在那里。 我唯一知道的是“空格,字母,字母,数字,数字,数字,数字,数字,数字,空格”模式。吉科DB544345

我一直在为这个“面具”寻找正确的词,但找不到答案。感谢您的帮助。

【问题讨论】:

  • 好的,我会检查的,谢谢。也许我们可以通过查找所有空格,查看它后面的字符串是否是这个长度,然后检查它是否是正确的格式来解决这个问题?
  • @pnuts 我同意你的观点,VBA 更适合非黑客解决方案(因此评论赞成),但在你的第二条评论中......如果你可以在你可以评估的空间之间分割这些块一个 8 字符块,其数组公式基本上根据 UNICODE 范围转换每个字符。大写字母为 2,数字为 1,其他任何数字为 0。将该数组中的每个数字提升到其在字符串中的索引的指数。总结他们。并检查你的答案是否等于 516。是的,我已经写了那个公式。
  • @pnuts 出于某种原因,在公式中进行这项工作的挑战让我很感兴趣。困难的部分是将两个步骤结合起来:生成块和执行测试。在一个公式中生成所有可能块的数组并不难。测试成分当然可以在一个公式中。将两者结合起来会很奇怪。
  • @pnuts 确实更简单。对于这个特定的简单模式,您可以对其中的大部分进行数字检查。旁注:我认为在这样的问题上使用代码通常很容易,但我发现自己并没有在 Excel 中大力推动这种情况,因为即使作为一名程序员,我也知道存在的长期问题。但是,使用公式会导致很多关于内置函数缺陷和怪癖的黑客攻击。
  • @pnuts 看起来我的潜意识不想放弃这个问题...我认为如果数字部分以破折号开头或包含句点,您的方法会发现错误的匹配项。

标签: excel vba find excel-formula wildcard


【解决方案1】:

由于 cmets 众多,我创建了一个可能代表 OP 正在处理的内容的最小示例:

A1:123456789 DB544345 asdfg asdfghjk
A2:creating dummy data is a DB544345 pain
A3:DB5443456 and soething else

使用文本到列(以空格作为分隔符)解析 ColumnB 中的副本,然后应用:

=IFERROR(IF(AND(LEN(B1)=8,CODE(LEFT(B1))>64,CODE(LEFT(B1))<91,CODE(MID(B1,2,1))>64,CODE(MID(B1,2,1))<91,ISNUMBER(RIGHT(B1,6)*1),RIGHT(B1,6)*1>99999),B1,""),"")

到 K1,将其复制到 P1,然后复制到 K1:P1。

【讨论】:

  • 这是一个很好的答案。它很乱,需要很多空间(如果有很多空格字符),并且不是实时更新(因为缺少更好的词),但是 如果 OP 的主要议程是尽快提取答案,这就是蛮力的方式来做到这一点。根据看不见的 OP 结构的结构以及他是否愿意支持它,这可能是最好的主意。对于一个不那么蛮力的解决方案,我发布了一个替代方案,它似乎可以在一个单元格公式中完成所有这些。
  • 哦,不过只有一件事。你的MID 函数不应该是MID(B1,2,1) 而不是MID(B1,1,1)
【解决方案2】:

针对此类问题的简明“仅内置函数”解决方案需要进行一些修改,因为由于内置 Excel 公式中的缺陷和怪癖,许多尝试将陷入死胡同或需要变通方法。我更喜欢单单元格公式,因为它们对一般电子表格结构的影响最小。但是,由于上面列出的限制,复杂的单单元格解决方案通常以相当长和繁琐为代价(这个答案在我的 Excel 公式栏中仍然只有两行)。我回到您的问题并拼凑出一个公式,该公式可以(据我测试)使用单个单元格公式提取此模式的第一次出现。这是一个数组公式(Ctrl+Shift+Enter 而不是 Enter),它假定您的数据在 A2 中。如果未找到匹配项,此粗略公式将返回前 8 个字符,如果字符串短于 10 个字符,则抛出 #REF。

=MID(A2,MIN(IF(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9))),1)=" ",IF(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+9,1)=" ",IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+1,1))>64,IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+1,1))<91,IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+2,1))>64,IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+2,1))<91,IF(IFERROR(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+3,6)*1>99999,FALSE),ROW(INDIRECT("A1:A"&(LEN(A2)-9)))))))))))+1,8)

让我尝试至少在高层次上分解它。我们将正文分成每一个可能的十个字符块,以便我们可以使用@pnuts 的建议来测试每个块,以验证前两个字符的Unicode 值,并对字符串的其余部分运行ISNUMBER 检查。第一个块在我的公式中重复出现。它生成一个从 1 到 n-9 的数字列表,其中 n 是我们的主要文本字符串的长度。

ROW(INDIRECT("A1:A"&(LEN(A2)-9)))

假设我们的字符串长度为 40 个字符,并将上面的公式替换为 {1...31}。使用这个数字序列生成,我们可以检查字符 1 到 31 是否为空格:

IF(MID(A2,{1...31},1)=" "

然后我们可以检查字符 10 到 40 是否为空格:

IF(MID(A2,{1...31}+9,1)=" "

然后我们可以检查字符 2 到 32 是否是大写字母:

IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+1,1))>64,
IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+1,1))<91

然后我们可以检查字符 3 到 33 是​​否是大写字母:

IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+2,1))>64,
IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+2,1))<91

然后我们可以检查字符串4到9、5到10、...、33到38、34到39是否是六位数字:

IF(IFERROR(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+3,6)*1>99999,FALSE)

如果所有条件都为 TRUE,则该 10 位块测试将通过原始数组 {1...31} 的另一个实例返回其在字符串中的第一个字符的索引。否则它什么也不返回。我们取所有返回索引的Min,然后使用Mid函数来抓取上述最小索引确定的8位字符串:

=MID(A2,MIN(matching index list)+1,8)

【讨论】:

  • @pnuts 我在一台 17 英寸的笔记本电脑上,所以屏幕很宽。当他说“空格,字母,字母,数字,数字,数字,数字,数字,数字,空格”,总是有一个尾随空格。我可以通过几种方法修改它以适应作为字符串最后 8 个字符的 ID。实际上最简单的方法是从 1 到 n-8(而不是 n-9)和然后放一个 IFERROR(我当前对尾随空格的检查,TRUE)。未经测试,但我认为这可行。
  • @pnuts 您建议的字符串中没有有效的匹配项。你那里只有5个号码。动态的!是的!这就是我逃避的词!
  • @pnuts 我可以通过多种方式解决没有有效答案的字符串。最简单的方法是获取TRIM(MID(A2,MIN(matching index list),9)) 而不是MID(A2,MIN(matching index list)+1, 8)。后者导致在没有有效发现的情况下返回的 0 变成 MID 函数的起始索引 1。
  • @pnuts 我当然明白这一点。我不介意。不知道为什么我一直在搞砸它。
【解决方案3】:

如果我们假设开头和结尾的SPACE 只是为了将ID 与字符串的其余部分区分开来,我认为这将起作用;因此,如果 ID 位于字符串的开头或结尾,则不会出现。此公式不区分大小写。如果需要区分大小写,我们可以进行字符代码比较。

=LOOKUP(2,1/((LEFT(myArr,2)>="AA")*(LEFT(myArr,2)<="ZZ")*(LEN(myArr)=8)*ISNUMBER(-RIGHT(myArr,6))),myArr)

myArr 指的是:

=TRIM(MID(SUBSTITUTE(TRIM(Sheet2!A1)," ",REPT(" ",99)),(ROW(INDIRECT("1:10"))-1)*99+1,99))

如果 myArr 最初是用 B1 中的光标定义的,如图所示引用 A1,它将调整为引用出现名称的单元格左侧一列的单元格。

1:10 中的10 是字符串中的最大字数 -- 可以根据需要进行调整。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-30
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 2021-02-11
    • 1970-01-01
    • 2015-03-21
    • 2021-04-06
    相关资源
    最近更新 更多