Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel 如何从字符串中获取整数?_Excel_Vba - Fatal编程技术网

Excel 如何从字符串中获取整数?

Excel 如何从字符串中获取整数?,excel,vba,Excel,Vba,我从旧文件中提取文本,需要将数字数据放在字符串中 字符串如下所示: "season: 1983 colony: 23 colony weight: 4 kg yeild: 12 kg "season: 1983 colony:- colony weight: 5 kg yeild: 14 kg" 我创建了一个函数,它接受一个原始数据字符串并返回一个整数数组 Function getClearBeeData(rawData As Variant) As Intege

我从旧文件中提取文本,需要将数字数据放在字符串中

字符串如下所示:

"season: 1983 colony: 23 colony weight: 4 kg yeild: 12 kg
"season: 1983 colony:- colony weight: 5 kg yeild: 14 kg"
我创建了一个函数,它接受一个原始数据字符串并返回一个整数数组

Function getClearBeeData(rawData As Variant) As Integer()
  Dim retValue(4) As Integer 'array where each found number stored
  Dim strTempString As String 'temporary string to hold current number
  Dim i, k As Integer 'i counter for original string, k counter for array position
  Dim token As Boolean 'token shows whether previous chars were number
  token = False
  
  For i = 1 To Len(rawData)   'go through original string
  
    If IsNumeric(Mid(rawData, i, 1)) Then   'if current char is numeric
      strTempString = strTempString & Mid(rawData, i, 1)  'add current char to remporary string
      token = True  'show that current position is within numbers
    ElseIf Mid(rawData, i, 1) = Chr(45) Then  'in string a symbol "-" can appear
      strTempString = "0"
      token = True
    ElseIf Not IsNumeric(Mid(rawData, i, 1)) And token = True Then  'if current char is not numeric and token shows that previous char was number
      retValue(k) = CInt(strTempString)   'convert temporary string to int and write in to the array
      k = k + 1   'go to next array position
      token = False   'switch token to show that current position is not within numbers
      strTempString = ""  'delete stored data from temporary string
    End If
    
  Next
  
  If Len(strTempString) > 0 Then
    retValue(k) = CInt(strTempString) 'if original string ended with numbers, write that numbers to array
  End If
  getClearBeeData = retValue
End Function
测试子系统以打印数据

Sub printClearBeeData()
  Dim rawData As String
  Dim clearDataArr() As Integer
  Dim i As Integer
  rawData = "season: 1983 colony: 12 colony weight: - kg yeild: 16 kg"
  clearDataArr = getClearBeeData(rawData)
  For i = LBound(clearDataArr) To UBound(clearDataArr) - 1
    Debug.Print clearDataArr(i)
  Next
End Sub
一切正常。我能做得更好吗?因为我一个人工作,没有人能进行代码审查。
我没有使用正则表达式,因为我不知道它们。

因为您的字符串模式总是相同的,其中一个或多个子字符串可以表示为-,正则表达式可以成为检索这些子字符串的简单、易于实现的工具。一个非常基本的示例可以帮助您继续:

Sub Test()

Dim rawData As String, ClearBeeData as Object

rawData = "season: 1983 colony: 12 colony weight: - kg yeild: 16 kg"
With CreateObject("vbscript.regexp")
    .Global = True
    .Pattern = "\d+|-"
    Set ClearBeeData = .Execute(rawData)
End With

For Each el In ClearBeeData
    Debug.Print Val(el)
Next

End Sub
@Peh提供的链接将为您提供大量信息,但这里有一些小评论:

.Global=True-如果设置为False,我们还可以检索第一个匹配项。当设置为True时,我们可以检索所有匹配项。 .Pattern=\d+|--在完整字符串中搜索的非常基本的模式,其中\d只是字符类[0-9]的缩写,+搜索至少一个字符或更长的子字符串。管道符号表示左右,如果位置不包含任何数字,我们可以搜索-或者。 .执行…-将返回找到的匹配项的Matchcollection类型对象。请注意,如果找不到匹配项,则会产生错误。当字符串具有相同的模式时,这里没有什么大不了的,但是为了将来的参考,您可能希望在尝试.Execute之前包含一个.Test。 Valel-由于返回集合中的所有元素都是文本,如果您愿意,我们可以使用Val将它们作为数字返回。很酷的特性是Val-将返回0。因此,对于上述示例,您的结果将是:

1983
12
0
16

由于您的字符串模式总是相同的,其中一个或多个子字符串可以用-表示,因此正则表达式可以成为检索这些子字符串的简单、易于实现的工具。一个非常基本的示例可以帮助您继续:

Sub Test()

Dim rawData As String, ClearBeeData as Object

rawData = "season: 1983 colony: 12 colony weight: - kg yeild: 16 kg"
With CreateObject("vbscript.regexp")
    .Global = True
    .Pattern = "\d+|-"
    Set ClearBeeData = .Execute(rawData)
End With

For Each el In ClearBeeData
    Debug.Print Val(el)
Next

End Sub
@Peh提供的链接将为您提供大量信息,但这里有一些小评论:

.Global=True-如果设置为False,我们还可以检索第一个匹配项。当设置为True时,我们可以检索所有匹配项。 .Pattern=\d+|--在完整字符串中搜索的非常基本的模式,其中\d只是字符类[0-9]的缩写,+搜索至少一个字符或更长的子字符串。管道符号表示左右,如果位置不包含任何数字,我们可以搜索-或者。 .执行…-将返回找到的匹配项的Matchcollection类型对象。请注意,如果找不到匹配项,则会产生错误。当字符串具有相同的模式时,这里没有什么大不了的,但是为了将来的参考,您可能希望在尝试.Execute之前包含一个.Test。 Valel-由于返回集合中的所有元素都是文本,如果您愿意,我们可以使用Val将它们作为数字返回。很酷的特性是Val-将返回0。因此,对于上述示例,您的结果将是:

1983
12
0
16

请也测试一下这个标准的VBA代码。它比你的短一点,也简单一点:

Private Function extractIntegers(rowData As String, strDelim As String) As Variant
 Dim arr As Variant, arrInt(3) As Variant, i As Long

 arr = Split(rowData, strDelim)

 For i = 1 To UBound(arr)
    arrInt(i - 1) = val(arr(i))
 Next i
 extractIntegers = arrInt
End Function
测试程序如下:

Sub testexractIntegers()
  Dim rowData As String, El As Variant, arrInt As Variant
  rowData = "season: 1983 colony: 23 colony weight: 4 kg yeild: 12 kg"
  'rowData = "season: 1983 colony: - colony weight: 4 kg yeild: 12 kg"
  arrInt = extractIntegers(rowData, ": ")
  For Each El In arrInt
    Debug.Print Int(El)
  Next
End Sub

如果取消注释第二个rowData定义,其中包含-,则该数组将为该特定数组元素返回0,请同时测试此标准VBA代码。它比你的短一点,也简单一点:

Private Function extractIntegers(rowData As String, strDelim As String) As Variant
 Dim arr As Variant, arrInt(3) As Variant, i As Long

 arr = Split(rowData, strDelim)

 For i = 1 To UBound(arr)
    arrInt(i - 1) = val(arr(i))
 Next i
 extractIntegers = arrInt
End Function
测试程序如下:

Sub testexractIntegers()
  Dim rowData As String, El As Variant, arrInt As Variant
  rowData = "season: 1983 colony: 23 colony weight: 4 kg yeild: 12 kg"
  'rowData = "season: 1983 colony: - colony weight: 4 kg yeild: 12 kg"
  arrInt = extractIntegers(rowData, ": ")
  For Each El In arrInt
    Debug.Print Int(El)
  Next
End Sub

如果取消注释第二个rowData定义,其中包含-,则该数组将为该特定数组元素返回0。该解决方案不依赖于regexp,但要求数字始终由空格包围

该函数返回索引与数字的脚本字典,其中索引是原始数据字符串中数字的第一个字符,数字是转换为Double类型的数字字符串

选项显式 子测试GetClearBeeData 将mySD设置为脚本.Dictionary 设置mySD=getClearBeeDataseason:1983菌落:-菌落重量:5千克yeild:14千克 Dim myItem作为变体 对于mySD中的每个myItem 调试.打印myItem,mySD.ItemmyItem 下一个 端接头 函数getClearBeeDataByVal ipRawData作为字符串作为脚本.Dictionary Dim myItems作为变体 myItems=SplitReplaceipRawData,-,0 Dim myItem作为变体 将myNumbers设置为脚本。字典:设置myNumbers=新建脚本。字典 变暗myLen的长度:myLen=1 对于myItems中的每个myItem 如果是numericmyitem,那么 MyNumber.添加myLen、CDblmyItem 如果结束 myLen=myLen+LenmyItem+1 下一个 设置getClearBeeData=myNumbers 端函数
一种解决方案,它不依赖于regexp,但要求数字总是被空格包围

该函数返回索引与数字的脚本字典,其中索引是原始数据字符串中数字的第一个字符,数字是转换为Double类型的数字字符串

选项显式 子测试GetClearBeeData 将mySD设置为脚本.Dictionary 设置mySD=getClearBeeDataseason:1983菌落:-菌落重量:5千克yeild:14千克 Dim myItem作为变体 对于mySD中的每个myItem 调试.打印myItem,mySD.ItemmyItem 下一个 端接头 函数getClearBeeDataByVal ipRawData作为字符串作为脚本.Dictionary Dim myItems作为变体 myItems=SplitReplaceipRawData,-,0 Dim myItem作为变体 将myNumbers设置为脚本。字典:设置myNumbers=新建脚本。字典 变暗myLen的长度:myLen=1 对于myItems中的每个myItem 如果是numericmyitem,那么 MyNumber.添加myLen、CDblmyItem 如果结束 myLen=myLen+LenmyItem+1 下一个 设置getClearBeeData=myNumbers 端函数 结合过滤器的拆分只允许一个循环

为了好玩,除了@FaneDuru的有效答案之外,我还演示了如何将Split函数与Filter结合使用,从而避免通过第二个循环在帮助函数中额外传输数组项

Sub TrickySplit()
    Dim rawData As String
    rawData = "season: 1983 colony: 12 colony weight: - kg yeild: 16 kg"

    '[1] split to tokens omitting the 1st element "seasons"
    '    ~> 1983 colony, 12 colony weight, - kg yeild, 16 kg
    Dim words: words = Split(rawData, ": "): words = Filter(words, words(0), False)

    '[2] convert number strings or "-" to values
    Dim i: For i = 0 To UBound(words): words(i) = Val(words(i)): Next

    '[3] optional (display results in VB Editors Immediate Window
    '    ~> 1983,12,0,16
    Debug.Print Join(words, ",")
End Sub
进一步提示

ad[1]:经典的通过分隔符拆分:生成基于0的数组:

   season|1983 colony|12 colony weight|- kg yeild|16 kg 
第一项words0~>季节不需要,可通过过滤功能立即删除,从而产生:

   1983 colony, 12 colony weight, - kg yeild, 16 kg
ad[2]:Val函数wordsi=Valwordsi使用忽略以下字符的事实,甚至将-0解释为0

因此,不必通过wordsi=ValSplitwordsi,0执行理论上的第二次拆分来删除附录字符串。

拆分与筛选器组合只允许一个循环

为了好玩,除了@FaneDuru的有效答案之外,我还演示了如何将Split函数与Filter结合使用,从而避免通过第二个循环在帮助函数中额外传输数组项

Sub TrickySplit()
    Dim rawData As String
    rawData = "season: 1983 colony: 12 colony weight: - kg yeild: 16 kg"

    '[1] split to tokens omitting the 1st element "seasons"
    '    ~> 1983 colony, 12 colony weight, - kg yeild, 16 kg
    Dim words: words = Split(rawData, ": "): words = Filter(words, words(0), False)

    '[2] convert number strings or "-" to values
    Dim i: For i = 0 To UBound(words): words(i) = Val(words(i)): Next

    '[3] optional (display results in VB Editors Immediate Window
    '    ~> 1983,12,0,16
    Debug.Print Join(words, ",")
End Sub
进一步提示

ad[1]:经典的通过分隔符拆分:生成基于0的数组:

   season|1983 colony|12 colony weight|- kg yeild|16 kg 
第一项words0~>季节不需要,可通过过滤功能立即删除,从而产生:

   1983 colony, 12 colony weight, - kg yeild, 16 kg
ad[2]:Val函数wordsi=Valwordsi使用忽略以下字符的事实,甚至将-0解释为0



因此,没有必要通过wordsi=ValSplitwordsi,0执行理论上的二次拆分来删除附录字符串。

代码运行时,有一个地方可以进行代码检查,名称如下:因此他们可以在这方面帮助您:我注意到了最后几句话,因为您有意避免使用regex,但我认为这是一个有效且相当简单的选择。哇,谢谢。JvdV,是的,我感觉到了正则表达式的威力:但是需要一些练习。我建议你研究一下正则表达式和正则表达式。这将很容易解决您的问题。你看,当代码运行时,有一个地方可以进行代码检查,名称如下:所以他们可以在这方面帮助你:我刚刚注意到最后几句话,因为你故意避免使用正则表达式,但我认为这是一个有效且相当简单的选择。哇,谢谢。JvdV,是的,我感觉到了正则表达式的威力:但是需要一些练习。我建议你研究一下正则表达式和正则表达式。这将很容易解决您的问题。看。非常感谢,它看起来比我的方法短得多,也容易得多。我将研究这个主题:比如你对这个有效答案的附加有用评论+:。仅供参考,我可能也对我迟交的答案感兴趣。非常感谢,它看起来比我的方法短得多,也容易得多。我将研究这个主题:比如你对这个有效答案的附加有用评论+:。仅供参考,我可能对我迟交的答案也感兴趣。谢谢,它很有效。但只有当我们基于字符串总是有:作为分隔符的想法时。我只是想做一个通用的方法。虽然我更喜欢在我的程序中使用您的解决方案,因为它更加清晰和简单。@HuskyTheFur:您是否也有不同的分隔符?在这种情况下,将创建一个strDelim变量,并根据需要进行调整。我将修改代码以接受变量分隔符。。。改编!是的,我想到了一个适合分隔符的变量。FaneDuru,有趣的替代方法:arrInti-1=valarri…看看当您查找带有-而不是数字=。对你的答案投了赞成票。谢谢,它起作用了。但只有当我们基于字符串总是有:作为分隔符的想法时。我只是想做一个通用的方法。虽然我更喜欢在我的程序中使用您的解决方案,因为它更加清晰和简单。@HuskyTheFur:您是否也有不同的分隔符?在这种情况下,将创建一个strDelim变量,并根据需要进行调整。我将修改代码以接受变量分隔符。。。改编!是的,我想到了一个适合分隔符的变量。FaneDuru,有趣的替代方法:arrInti-1=valarri…看看当您查找带有-而不是数字=。对你的答案投了赞成票。嗯,显然我必须读一点关于脚本字典的内容,一点也不懂这个语法。嗯,显然我必须读一点关于脚本字典的内容,一点也不懂这个语法。数组过滤方式很有趣,但在
在他的情况下,从1开始数组元素迭代,第一个元素将被跳过。。。无论如何,这是一个有趣的想法,在特定的元素被排除在阵列的中间,并希望避免如果…结束如果。我会投票支持代码…谢谢你和我一样支持我的答案。总是友好和建设性的回答你自己。继续做好工作+@FaneDuru Thx以获取反馈。-响应从1迭代的提示:这只考虑显示,但不会更改单词数组本身:-;同意。但是,在这种情况下,完成工作后无需保留已清洁的阵列,我认为…:有趣的是数组过滤方式,但在本例中,从1开始数组元素迭代,将跳过第一个元素。。。无论如何,这是一个有趣的想法,在特定的元素被排除在阵列的中间,并希望避免如果…结束如果。我会投票支持代码…谢谢你和我一样支持我的答案。总是友好和建设性的回答你自己。继续做好工作+@FaneDuru Thx以获取反馈。-响应从1迭代的提示:这只考虑显示,但不会更改单词数组本身:-;同意。但是,在这种情况下,完成工作后无需保留已清洁的阵列,我认为…: