VBA parsing of numeric ranges from string - parsing

I need to parse numeric range from User Form (VBA, Excel).
For example: {1-3,5,9} -> {1,2,3,5,9,}
The question has already been discussed here:
Advanced parsing of numeric ranges from string
The task is quite standart, is there any ready-made solution for VBA?

I am assuming that the encompassing braces are not part of the string. Consider the following UDF:
Public Function DashFiller(sIn As String) As String
Dim N As Long, NN As Long
DashFiller = ""
ary = Split(sIn, ",")
For N = LBound(ary) To UBound(ary)
If InStr(1, ary(N), "-") > 0 Then
ary2 = Split(ary(N), "-")
ary(N) = ary2(0)
For NN = ary2(0) + 1 To ary2(1)
ary(N) = ary(N) & "," & NN
Next NN
End If
Next N
DashFiller = Join(ary, ",")
End Function
So if A1 contains:
1-2,3,4,5,9-12
and B1 contains:
=DashFiller(A1)
then B1 would display:
1,2,3,4,5,9,10,11,12

Related

Trying to make function which takes string as input and returns no. of words in whole string

**It takes Input as a string such as this - 'Nice one'
And Output gives - 4,3 (which is no. Of words in sentence or string)
**
function countx(str)
local count = {}
for i = 1, string.len(str) do
s = ''
while (i<=string.len(str) and string.sub(str, i, i) ~= ' ' ) do
s = s .. string.sub(str, i, i)
i = i+1
end
if (string.len(s)>0) then
table.insert(count,string.len(s))
end
end
return table.concat(count, ',')
end
You can find a simple alternative with your new requirements:
function CountWordLength (String)
local Results = { }
local Continue = true
local Position = 1
local SpacePosition
while Continue do
SpacePosition = string.find(String, " ", Position)
if SpacePosition then
Results[#Results + 1] = SpacePosition - Position
Position = SpacePosition + 1
-- if needed to print the string
-- local SubString = String:sub(Position, SpacePosition)
-- print(SubString)
else
Continue = false
end
end
Results[#Results + 1] = #String - Position + 1
return Results
end
Results = CountWordLength('I am a boy')
for Index, Value in ipairs(Results) do
print(Value)
end
Which gives the following results:
1
2
1
3
def countLenWords(s):
s=s.split(" ")
s=map(len,s)
s=map(str,s)
s=list(s)
return s
The above functions returns a list containing number of characters in each word
s=s.split(" ") splits string with delimiter " " (space)
s=map(len,s) maps the words into length of the words in int
s=map(str,s) maps the values into string
s=list(s) converts map object to list
Short version of above function (all in one line)
def countLenWords(s):
return list(map(str,map(len,s.split(" "))))
-- Localise for performance.
local insert = table.insert
local text = 'I am a poor boy straight. I do not need sympathy'
local function word_lengths (text)
local lengths = {}
for word in text:gmatch '[%l%u]+' do
insert (lengths, word:len())
end
return lengths
end
print ('{' .. table.concat (word_lengths (text), ', ') .. '}')
gmatch returns an iterator over matches of a pattern in a string.
[%l%u]+ is a Lua regular expression (see http://lua-users.org/wiki/PatternsTutorial) matching at least one lowercase or uppercase letter:
[] is a character class: a set of characters. It matches anything inside brackets, e.g. [ab] will match both a and b,
%l is any lowercase Latin letter,
%u is any uppercase Latin letter,
+ means one or more repeats.
Therefore, text:gmatch '[%l%u]+' will return an iterator that will produce words, consisting of Latin letters, one by one, until text is over. This iterator is used in generic for (see https://www.lua.org/pil/4.3.5.html); and on any iteration word will contain a full match of the regular expression.

DXL to truncate Object number

I inherited some DXL code to truncate the Object Number to exclude the last “0”
This works fine for paragraphs numbers less than 10 (or a double digit number). I’ll admit to be new to DXL, but this code stumps me as I am not familiar with RegExp. I know that those on this forum will look at this and get the answer and I will then learn and move forward.
Here is the code:
string s = number(obj)
Regexp paraNumExp = regexp2 "[0-9](\\.[0-9])*"
if(paraNumExp s) obj.attrDXLName = s[match 0]
delete paraNumExp
This is what is produces:
AbsNum, ObjNumber, DXL Attribute
Here is the DXL code for the attached file (output from the test module)
(DXL) Paragraph Number 1
string s = number(obj)
Regexp paraNumExp = regexp2 "[1-9](\\.[1-9])*"
if(paraNumExp s) obj.attrDXLName = s[match 0]
delete paraNumExp
(DXL) Paragraph Number 2
string s = number(obj)
Regexp paraNumExp = regexp2 "^[0-9]+\\.[0-9]+"
if(paraNumExp s) obj.attrDXLName = s[match 0]
delete paraNumExp
(DXL) Paragraph Number 4
Regexp reZero = regexp2 "(\\.0)-"
string s = number(obj)
if (reZero s) {
obj.attrDXLName = s[0:start 1-1]
}
delete reZero
DOORS output with what I want
Not super sure, what you are trying to accomplish, or what is the deeper problem here. But to answer your question for "truncating the pending zeros", I would suggest to use "start" and "end" methods here, e.g.:
Regexp reZero = regexp2 "(\\.0)-"
Module m = current
filtering off
Object o
for o in m do {
string strON = number( o )
string strTruncated = strON
if (reZero strON) {
strTruncated = strON[0:start 1-1] "" strON[end 1+1:]
}
print "" identifier( o ) ": " strON " => '" strTruncated "'\n"
}
With your help and a little bugging of a colleague, I got the results I need.
This is the DXL code:
// Define reZero to detect ".0-"
Regexp reZero = regexp2 "(\\.0)-"
// Get the Object Number
string s = number(obj)
if (reZero s) {
// Found ".0-"? Strip off ".0-" and all following that string
obj.attrDXLName = s[0:start 1-1]
} else {
// Did not find ".0-". Use complete object number.
obj.attrDXLName = s
}
delete reZero

Extract repeated URL parameter strings [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I want to extract c=; t=; s= values to columns, in delimited string with commas in a Google sheet. The values could be repeated multiple times up to 10.
c= are always only two capital letters.
For example:
A examples
&t=clothes&t=bags&s=other&c=US&c=FR&c=GB
&c=NL
&t=glasses
&c=US&c=FR&c=GB&t=watches&t=necklaces&s=other&s=required
B column (c= strings)
US, FR, GB
C column (t= strings)
clothes,bags
D column (s= strings)
other, required
try,
=join(",", split(mid(A1, find("&c=", A1)+3, len(A1)), "&c="))
google-spreadsheet
=REGEXEXTRACT(SUBSTITUTE(A1,"&c=",","),"((?:[A-Z]{2},?)+)")
=REGEXREPLACE(REGEXREPLACE(A1,"([^A-Z]*)([A-Z]{2})([^A-Z]*)","$2, "),".$",)
[A-Z] Any 2 letter uppercase word
[^A-Z] Not a 2 letter uppercase word
Depending on your input, you may decide to follow the logic: Take all letters in Upper Case and split them by a space. The letter in UpperCase in the standard US/UK alphabet are 26 and are between 65 and 90 in the ASCII table.
Thus, looping from each value and checking whether it is between 65 and 90 would be ok:
Public Function GetUpperCase(inputVal As String) As String
Dim resultVal As String
Dim i As Long
For i = 1 To Len(inputVal)
If Asc(Mid(inputVal, i, 1)) >= 65 And Asc(Mid(inputVal, i, 1)) <= 90 Then
resultVal = resultVal & Mid(inputVal, i, 1)
Else
resultVal = resultVal & " "
End If
Next i
GetUpperCase = WorksheetFunction.Trim(resultVal)
End Function
At the end, WorksheetFunction.Trim is quite handy, because it removes the multiple spaces and it reduces them to a single one:
I prefer Jeeped's solution, but in case you were looking for a VBA implementation.
Private Sub parse_c()
Dim result As String
Dim lr As Long
lr = Cells(Rows.Count, 1).End(xlUp).Row
result = ""
For Each cell In Range("A1:A" & lr)
For i = 1 To Len(cell)
If (Mid(cell, i, 2) = "c=") Then
If (result = "") Then
result = Mid(cell, i + 2, 2)
Else
result = result & ", " & Mid(cell, i + 2, 2)
End If
End If
Next i
cell.Offset(0, 1) = result
result = ""
Next cell
End Sub
Loops through all active cells in Column A and substracts all the countries with the desired delimiter.
tested: (also with some trickery, such as =cc=UK)

Find all occurences of exact string in range and list it

I want to create list of all occurences of "x" string in range. This is my sheet:
And I want to search all occurences and list them and give proper names:
For example for G2, I want "Beret Grey" string as result. I think that I need to use array formula or something like that.
Let me first preface this that vba would be much more robust, but this formula will get you there. It may be slow as it is an array type formula and is doing a lot of calculations. These calculations only expound exponentially as the number of cells with them in it increases:
=IFERROR(INDEX(A:A,AGGREGATE(15,6,ROW($B$2:$G$7)/($B$2:$G$7="x"),ROW(1:1))) & " " & INDEX($1:$1,AGGREGATE(15,6,COLUMN(INDEX(A:G,AGGREGATE(15,6,ROW($B$2:$G$7)/($B$2:$G$7="x"),ROW(1:1)),0))/(INDEX(A:G,AGGREGATE(15,6,ROW($B$2:$G$7)/($B$2:$G$7="x"),ROW(1:1)),0)="x"),ROW(1:1)-COUNTIF($B$1:INDEX(G:G,AGGREGATE(15,6,ROW($B$2:$G$7)/($B$2:$G$7="x"),ROW(1:1)) -1),"x"))),"")
You will need to expand the range to what you need. Change all the $B$2:$G$7 to $B$2:$N$29. Do not use full column references outside those that I have used. It will kill Excel.
Also note what is and what is not relative references, they need to remain the same or you will get errors as the formula is dragged/copied down.
As simple UDF to do what you want:
Function findMatch(rng As Range, crit As String, inst As Long) As String
Dim rngArr() As Variant
rngArr = rng.Value
Dim i&, j&, k&
k = 0
If k > Application.WorksheetFunction.CountIf(rng, crit) Then
findMatch = ""
Exit Function
End If
For i = LBound(rngArr, 1) + 1 To UBound(rngArr, 1)
For j = LBound(rngArr, 2) + 1 To UBound(rngArr, 2)
If rngArr(i, j) = crit Then
k = k + 1
If k = inst Then
findMatch = rngArr(i, 1) & " " & rngArr(1, j)
Exit Function
End If
End If
Next j
Next i
then you would call it like this:
=findMatch($A$1:$G$7,"x",ROW(1:1))
And drag/copy down.

Open Office Spreadsheet (Calc) - Concatenate text cells with delimiters

I am using Open Office's spreadsheet program and am trying to concatenate several text cells together with delimeters. For example, suppose I have the cells below:
+--------+
| cell 1 |
+--------+
| cell 2 |
+--------+
| cell 3 |
+--------+
| cell 4 |
+--------+
| cell 5 |
+--------+
I would like to concatenate them with delimiters so that the result is in one cell like this one:
+----------------------------------------------+
| (cell 1),(cell 2),(cell 3),(cell 4),(cell 5) |
+----------------------------------------------+
My first thought was to try and make a macro or something, but I don't think open office supports those. Any ideas?
Thanks a lot Markus for finding a solution to this.
Here are some slightly more detailed instructions for the benefit of OpenOffice Basic newbies like myself. This applies to version 3.1:
Tools -> Macros -> Organize Macros -> OpenOffice.org Basic...
Now select from the explorer tree where you want your function live,
e.g. it can be in your own macro library (My Macros / Standard) or
stored directly in the current spreadsheet.
Now enter a new Macro name and click New to open the OO.org Basic IDE. You'll see a REM
statement and some stub Sub definitions. Delete all that and replace
it with:
Function STRJOIN(range, Optional delimiter As String, Optional before As String, Optional after As String)
Dim row, col As Integer
Dim result, cell As String
result = ""
If IsMissing(delimiter) Then
delimiter = ","
End If
If IsMissing(before) Then
before = ""
End If
If IsMissing(after) Then
after = ""
End If
If NOT IsMissing(range) Then
If NOT IsArray(range) Then
result = before & range & after
Else
For row = LBound(range, 1) To UBound(range, 1)
For col = LBound(range, 2) To UBound(range, 2)
cell = range(row, col)
If cell <> 0 AND Len(Trim(cell)) <> 0 Then
If result <> "" Then
result = result & delimiter
End If
result = result & before & range(row, col) & after
End If
Next
Next
End If
End If
STRJOIN = result
End Function
The above code has some slight improvements from Markus' original:
Doesn't start with a delimiter when the first cell in the range is empty.
Allows optional choice of the delimiter (defaults to ","), and the
strings which go before and after each non-blank entry in the range
(default to "").
I renamed it STRJOIN since "join" is the typical name of this
function in several popular languages, such as Perl, Python, and Ruby.
Variables all lowercase
Now save the macro, go to the cell where you want the join to appear,
and type:
=STRJOIN(C3:C50)
replacing C3:C50 with the range of strings you want to join.
To customise the delimiter, instead use something like:
=STRJOIN(C3:C50; " / ")
If you wanted to join a bunch of email addresses, you could use:
=STRJOIN(C3:C50; ", "; "<"; ">")
and the result would be something like
<foo#bar.com>, <baz#qux.org>, <another#email.address>, <and#so.on>
Well, after a lot more searching and experimenting, I found you can make your own functions in calc. This is a function I made that does what I want:
Function STRCONCAT(range)
Dim Row, Col As Integer
Dim Result As String
Dim Temp As String
Result = ""
Temp = ""
If NOT IsMissing(range) Then
If NOT IsArray(range) Then
Result = "(" & range & ")"
Else
For Row = LBound(range, 1) To UBound(range, 1)
For Col = LBound(range, 2) To UBound(range, 2)
Temp = range(Row, Col)
Temp = Trim(Temp)
If range(Row, Col) <> 0 AND Len(Temp) <> 0 Then
If(NOT (Row = 1 AND Col = 1)) Then Result = Result & ", "
Result = Result & "(" & range(Row, Col) & ") "
End If
Next
Next
End If
End If
STRCONCAT = Result
End Function
Ever so often I'd enjoy the ease and quickness of replace & calculation Options as well as in general the quick handling & modifying Options, when once again sitting in front of a dumped-file-lists or whatsoever.
I never understood why they didn't include such an essential function right from the start, really.
It's based on Adam's script, but with the extension to swap CONCAT from horizontal to vertical, while still keeping the delimiters in order.
Function CONCAT2D(Optional range, Optional delx As String, Optional dely As String, _
Optional xcell As String, Optional cellx As String, _
Optional swop As Integer)
Dim xy(1), xyi(1), s(1) As Integer
Dim out, cell, del, dxy(1) As String
'ReDim range(2, 1) 'Gen.RandomMatrix 4 Debugging
'For i = LBound(range, 1) To UBound(range, 1)
' For j = LBound(range, 2) To UBound(range, 2)
' Randomize
' range(i,j) = Int((100 * Rnd) )
' Next
'Next
out = ""
If IsMissing(delx) Then : delx = "," : End If
If IsMissing(dely) Then : dely = delx() : End If
If IsMissing(xcell) Then : xcell = "" : End If
If IsMissing(cellx) Then : cellx = xcell() : End If
If IsMissing(swop) Then : swop = 0 : End If
dxy(0) = delx() : dxy(1) = dely()
xyi(0) = 1 : xyi(1) = 2
If swop = 0 Then : s(0) = 0 : s(1) = 1
Else s(0) = 1 : s(1) = 0 : End If
If NOT IsMissing(range) Then
If NOT IsArray(range) _
Then : out = xcell & range & cellx
Else del = delx
For xy(s(0)) = LBound(range, xyi(s(0))) To UBound(range, xyi(s(0))
For xy(s(1)) = LBound(range, xyi(s(1))) To UBound(range, xyi(s(1))
cell = range(xy(0), xy(1))
If cell <> 0 AND Len(Trim(cell)) <> 0 _
Then : If out <> "" Then : out = out & del : End If
out = out & xcell & cell & cellx
del = dxy(s(0))
End If
Next : del = dxy(s(1))
Next
End If
Else out = "ERR"
End If
CONCAT2D = out
End Function

Resources