Find and replace superscripts in PowerPoint - replace

Is there a way to customize the code below (for making subscripts and superscripts larger) to search for superscript a , b, c …. and replace them with numbers 1, 2, 3 …in PowerPoint.
Any help would be much appreciated.
Source for the code.
Sub BumpTheSubsAndSupers()
Dim oSl As Slide
Dim oSh As Shape
Dim x As Long
Dim dBumpBy As Double
dBumpBy = 4 ' number of points to bump sub/superscript by
' Check each slide
For Each oSl In ActivePresentation.Slides
' Check each shape on the slide
For Each oSh In oSl.Shapes
' Make sure it's got text
If oSh.HasTextFrame Then
If oSh.TextFrame.HasText Then
With oSh.TextFrame.TextRange
For x = 1 To .Runs.Count
If .Runs(x).Characters.Font.BaselineOffset <> 0 Then
' it's a sub/super; make it four points
' bigger than the text immediately prior:
.Runs(x).Characters.Font.Size = _
.Runs(x - 1).Characters.Font.Size + dBumpBy
End If ' it's a sub/superscript
Next x
End With ' textframe.textrange
End If ' .HasText
End If ' .HasTextFrame
Next oSh '
Next oSl
End Sub

Great question!
I've modified the code to do both (change the size and switch letters to numbers).
You can comment out whichever part you don't want if you like. There are doubtless more efficient ways of doing this (like splitting the array of letters once rather than once for each subscript) but it's all but instant on moderately sized files; the time it'd take to optimize it would probably exceed the time it'd save in use.
If you use letters from other alphabets as sub/superscripts, you'll want to add them to the OrdinalFromLetter function.
Option Explicit
Sub BumpTheSubsAndSupers()
Dim oSl As Slide
Dim oSh As Shape
Dim x As Long
Dim dBumpBy As Double
dBumpBy = 4 ' number of points to bump sub/superscript by
' Check each slide
For Each oSl In ActivePresentation.Slides
' Check each shape on the slide
For Each oSh In oSl.Shapes
' Make sure it's got text
If oSh.HasTextFrame Then
If oSh.TextFrame.HasText Then
With oSh.TextFrame.TextRange
For x = 1 To .Runs.Count
If .Runs(x).Characters.Font.BaselineOffset <> 0 Then
' it's a sub/super; make it four points
' bigger than the text immediately prior:
.Runs(x).Characters.Font.Size = _
.Runs(x - 1).Characters.Font.Size + dBumpBy
.Runs(x).Text = CStr(OrdinalFromLetter(.Runs(x)))
End If ' it's a sub/superscript
Next x
End With ' textframe.textrange
End If ' .HasText
End If ' .HasTextFrame
Next oSh '
Next oSl
End Sub
Function OrdinalFromLetter(sLetter As String) As Long
Dim x As Long
Dim aLetters As Variant
aLetters = Split("A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z", ",")
For x = LBound(aLetters) To UBound(aLetters)
If UCase(sLetter) = aLetters(x) Then
OrdinalFromLetter = x
Exit Function
End If
Next
End Function

Related

Microsoft Access: Group By Function and list out variances [duplicate]

I have a table that contains run numbers. This is then linked to a second table that contains the serial numbers of the panels that go through each run. I was wondering is it possible to design a query that will give for each run number the serial numbers.
I would like it in a table like:
Run Number1, First Serial Number for 1, Second Serial Number for 1, etc..
Run Number2, First Serial Number for 2, Second Serial Number for 2, etc..
I can get in in the form:
Run Number1, First Serial Number for 1
Run Number1, Second Serial Number for 1
Run Number2, First Serial Number for 2
Run Number2, Second Serial Number for 2
Is there a way to set this up?
You can use my DJoin function as this will accept SQL as the source, thus you won't need additional saved queries:
' Returns the joined (concatenated) values from a field of records having the same key.
' The joined values are stored in a collection which speeds up browsing a query or form
' as all joined values will be retrieved once only from the table or query.
' Null values and zero-length strings are ignored.
'
' If no values are found, Null is returned.
'
' The default separator of the joined values is a space.
' Optionally, any other separator can be specified.
'
' Syntax is held close to that of the native domain functions, DLookup, DCount, etc.
'
' Typical usage in a select query using a table (or query) as source:
'
' Select
' KeyField,
' DJoin("[ValueField]", "[Table]", "[KeyField] = " & [KeyField] & "") As Values
' From
' Table
' Group By
' KeyField
'
' The source can also be an SQL Select string:
'
' Select
' KeyField,
' DJoin("[ValueField]", "Select ValueField From SomeTable Order By SomeField", "[KeyField] = " & [KeyField] & "") As Values
' From
' Table
' Group By
' KeyField
'
' To clear the collection (cache), call DJoin with no arguments:
'
' DJoin
'
' Requires:
' CollectValues
'
' 2019-06-24, Cactus Data ApS, Gustav Brock
'
Public Function DJoin( _
Optional ByVal Expression As String, _
Optional ByVal Domain As String, _
Optional ByVal Criteria As String, _
Optional ByVal Delimiter As String = " ") _
As Variant
' Expected error codes to accept.
Const CannotAddKey As Long = 457
Const CannotReadKey As Long = 5
' SQL.
Const SqlMask As String = "Select {0} From {1} {2}"
Const SqlLead As String = "Select "
Const SubMask As String = "({0}) As T"
Const FilterMask As String = "Where {0}"
Static Values As New Collection
Dim Records As DAO.Recordset
Dim Sql As String
Dim SqlSub As String
Dim Filter As String
Dim Result As Variant
On Error GoTo Err_DJoin
If Expression = "" Then
' Erase the collection of keys.
Set Values = Nothing
Result = Null
Else
' Get the values.
' This will fail if the current criteria hasn't been added
' leaving Result empty.
Result = Values.Item(Criteria)
'
If IsEmpty(Result) Then
' The current criteria hasn't been added to the collection.
' Build SQL to lookup values.
If InStr(1, LTrim(Domain), SqlLead, vbTextCompare) = 1 Then
' Domain is an SQL expression.
SqlSub = Replace(SubMask, "{0}", Domain)
Else
' Domain is a table or query name.
SqlSub = Domain
End If
If Trim(Criteria) <> "" Then
' Build Where clause.
Filter = Replace(FilterMask, "{0}", Criteria)
End If
' Build final SQL.
Sql = Replace(Replace(Replace(SqlMask, "{0}", Expression), "{1}", SqlSub), "{2}", Filter)
' Look up the values to join.
Set Records = CurrentDb.OpenRecordset(Sql, dbOpenSnapshot)
CollectValues Records, Delimiter, Result
' Add the key and its joined values to the collection.
Values.Add Result, Criteria
End If
End If
' Return the joined values (or Null if none was found).
DJoin = Result
Exit_DJoin:
Exit Function
Err_DJoin:
Select Case Err
Case CannotAddKey
' Key is present, thus cannot be added again.
Resume Next
Case CannotReadKey
' Key is not present, thus cannot be read.
Resume Next
Case Else
' Some other error. Ignore.
Resume Exit_DJoin
End Select
End Function
' To be called from DJoin.
'
' Joins the content of the first field of a recordset to one string
' with a space as delimiter or an optional delimiter, returned by
' reference in parameter Result.
'
' 2019-06-11, Cactus Data ApS, Gustav Brock
'
Private Sub CollectValues( _
ByRef Records As DAO.Recordset, _
ByVal Delimiter As String, _
ByRef Result As Variant)
Dim SubRecords As DAO.Recordset
Dim Value As Variant
If Records.RecordCount > 0 Then
While Not Records.EOF
Value = Records.Fields(0).Value
If Records.Fields(0).IsComplex Then
' Multi-value field (or attachment field).
Set SubRecords = Records.Fields(0).Value
CollectValues SubRecords, Delimiter, Result
ElseIf Nz(Value) = "" Then
' Ignore Null values and zero-length strings.
ElseIf IsEmpty(Result) Then
' First value found.
Result = Value
Else
' Join subsequent values.
Result = Result & Delimiter & Value
End If
Records.MoveNext
Wend
Else
' No records found with the current criteria.
Result = Null
End If
Records.Close
End Sub
Full documentation can be found in my article:
Join (concat) values from one field from a table or query
If you don't have an account, browse to the link: Read the full article.
Code is also on GitHub: VBA.DJoin

VBA Regex: from last used row, in a column,get count of a matched pattern between another pattern

I'm new to VBA using regex. On a worksheet, I have a column with cells that have several specific names and between these names are several qualifiers. I need help to put together a VBA/macro code using regex to loop through the column and get the counts of the qualifiers between names and put the count value to the cell on the right of the name. The names all start with uppercase letters while the qualifiers start with a lower case letter. So i'm using ^[A-Z]* to match the names and ^[a-z]* for the qualifiers. Each value is in separate cells and the occurrences are random. So far I can only get total count of all qualifiers. I appreciate the help.
Like instead of RegEx
Adjust the values in the constants section.
Option Explicit
'START ****************************************************************** START'
' Title: Count Owners '
' Purpose: Counts the number of cells containing a string starting with '
' a lower-case character below a cell containing a string '
' starting with an upper-case character and writes the result '
' to the same row of the string starting with the upper-case '
' character, in another (specified) column. '
'******************************************************************************'
Sub CountOwners()
Const wsName As String = "Sheet1" ' Worksheet Name
Const rowHeader As Long = 3 ' Header Row
Const colOwner As Long = 2 ' Owner Column Number
Const colCount As Long = 3 ' Count Column Number
Dim rng As Range ' Owner Column, Owner Column Range,
' Count Column Range
Dim vntOwner As Variant ' Owner Array
Dim vntCount As Variant ' Count Array
Dim LneRinC As Long ' Last Non-Empty Row in Owner Column
Dim UB As Long ' Arrays Last Element Count
Dim lngOwner As Long ' Current Owner Element (Row)
Dim lngCount As Long ' (Current) Owner Count(er)
Dim i As Long ' First Arrays Element Counter
Dim j As Long ' Second Arrays Element Counter
Dim strChar As String * 1 ' Current Char
' IN WORKSHEET
' Define Owner Column.
Set rng = ThisWorkbook.Worksheets(wsName).Columns(colOwner)
' Using the Find method, try to define Owner Column Range.
Set rng = rng.Find("*", , xlFormulas, , , xlPrevious)
' Check if no data in Owner Column.
If rng Is Nothing Then GoTo NoData
' Calculate Last Non-Empty Row in Owner Column.
LneRinC = rng.Row
' Check if no Owners in Owner Column Range.
If LneRinC <= rowHeader Then GoTo NoOwners
' Define Owner Column Range.
Set rng = rng.Parent.Cells(rowHeader + 1, colOwner).Resize(LneRinC - rowHeader)
' Write values of Owner Column Range to Owner Array.
vntOwner = rng
' IN ARRAYS
' Define Arrays Last Element Count
UB = UBound(vntOwner)
' Resize Count Array (vntCount) to the size of Owner Array (vntOwner).
ReDim vntCount(1 To UB, 1 To 1)
' Loop through elements of Owner Array.
For i = 1 To UB
' Write first characterg of current element in Owner Array
' to Current Char.
strChar = Left$(vntOwner(i, 1), 1)
' Check if current char is an uppercase character.
If strChar Like "[A-Z]" Then
' Assign the value of the current row of Owner Array
' to Current Owner Element (Row).
lngOwner = i
' Reset Current Owner Element.
lngCount = 0
' Loop through the rest of the elements in Owner Array.
For j = i + 1 To UB
' Write first character of current element in Owner Array
' to Current Char.
strChar = Left$(vntOwner(j, 1), 1)
' Check if Current Char is an uppercase letter.
If strChar Like "[A-Z]" Then
' Reset First Arrays Element Counter.
i = j - 1
Exit For
Else
' Check if Current Char is a lowercase letter.
If strChar Like "[a-z]" Then
' Increase (Current) Owner Counter.
lngCount = lngCount + 1
End If
End If
Next
' Write value of (Current) Owner Counter to Count Array.
vntCount(lngOwner, 1) = lngCount
End If
Next
' IN WORKSHEET
' Define Count Column Range.
Set rng = rng.Offset(, colCount - colOwner)
' Write values of Count Array to Count Column Range.
rng = vntCount
ProgramError:
Exit Sub
NoData:
MsgBox "There is no data in Owner column (" & colOwner & ")."
GoTo ProgramError
NoOwners:
MsgBox "There are no Owners in Owner column (" & colOwner & ")."
GoTo ProgramError
End Sub
'******************************************************************************'
' Remarks: Values not starting with alpha characters are not counted. '
' Owner Column Range doesn't have to start with an Owner. '
' Owner Column Range can end with an Owner; the count will be 0. '
'END ********************************************************************** END'

Excel VBA RegEx that extracts numbers from price values in range (has commas, $ and -)

I have a field data extracted from a database which represents a range of values, but it's coming in Excel as a String format $86,000 - $162,000.
I need to extract the minimum value and the maximum value from each cell, so I need to extract the numeric portion of it, and ignore the $, - and the ,.
I've attached an image of the data I have, and the values I want to extract from it.
This is the closest pattern I got with RegEx, but I'ts not what I'm looking for.
Pattern = (\d+)(?:\.(\d{1,2}))?
Can anyone assist ?
Just wondering why Regex?
Function GetParts(priceRange As String) As Double()
Dim arr() As String
Dim parts() As Double
If InStr(1, priceRange, "-") > 0 Then
arr = Split(priceRange, "-")
ReDim parts(0 To UBound(arr))
Dim i As Long
For i = 0 To UBound(arr)
parts(i) = CDbl(Replace$(Replace$(Trim$(arr(i)), "$", ""), ",", ""))
Next i
End If
GetParts = parts
End Function
Sub test()
MsgBox GetParts("$14,000 - $1,234,567")(0) 'Minimum
End Sub
EDIT
Yet you could do this with regex to match the data string into the parts:
Function GetPartsRegEx(priceRange As String) As Variant
Dim arr() As Double
Dim pricePattern As String
pricePattern = "(\$?\d+[\,\.\d]*)"
'START EDIT
Static re As RegExp
If re Is Nothing Then
Set re = New RegExp
re.IgnoreCase = True
re.Global = True
re.Pattern = pricePattern & "\s*[\-]\s*" & pricePattern 'look for the pattern first
End If
Static nums As RegExp
If nums Is Nothing Then
Set nums = New RegExp
'to remove all non digits, except decimal point in case you have pennies
nums.Pattern = "[^0-9.]"
nums.Global = True
End If
'END EDIT
If re.test(priceRange) Then
ReDim arr(0 To 1) ' fill return array
arr(0) = CDbl(nums.Replace(re.Replace(priceRange, "$1"), ""))
arr(1) = CDbl(nums.Replace(re.Replace(priceRange, "$2"), ""))
Else
'do some error handling here
Exit Function
End If 'maybe throw error if no +ve test or
GetPartsRegEx = arr
End Function
Sub test()
MsgBox GetPartsRegEx("$1,005.45 - $1,234,567.88")(1)
End Sub
Here is quick Example Demo https://regex101.com/r/RTNlVF/1
Pattern "^\$(\d+\,\d+)\s\-\s\$(\d+\,\d+)"
Option Explicit
Private Sub Example()
Dim RegExp As New RegExp
Dim Pattern As String
Dim CelValue As String
Dim rng As Range
Dim Cel As Range
Set rng = ActiveWorkbook.Sheets("Sheet1" _
).Range("A2", Range("A9999" _
).End(xlUp))
For Each Cel In rng
DoEvents
Pattern = "^\$(\d+\,\d+)\s\-\s\$(\d+\,\d+)"
If Pattern <> "" Then
With RegExp
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = Pattern
End With
If RegExp.Test(Cel.Value) Then
' Debug.Print Cel.Value
Debug.Print RegExp.Replace(CStr(Cel), "$1")
Debug.Print RegExp.Replace(CStr(Cel), "$2")
End If
End If
Next
End Sub
Without a loop (but still no regex):
Sub Split()
With Columns("B:B")
.Replace What:="$", Replacement:=""
Application.CutCopyMode = False
.TextToColumns Destination:=Range("B1"), DataType:=xlDelimited, Other:=True, OtherChar:="-", FieldInfo:=Array(Array(1, 1), Array(2, 1))
End With
Columns("B:C").Insert Shift:=xlToRight
Columns("D:E").NumberFormat = "0"
Range("D1").FormulaR1C1 = "Min Value"
Range("E1").FormulaR1C1 = "Max Value"
With Range("D1:E1").Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 12611584
End With
With Range("D1:E1").Font
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
End With
End Sub
I made this function:
Hope it helps.
Code:
Function ExtractNumber(ByVal TextInput As String, _
Optional ByVal Position As Byte = 0, _
Optional ByVal Delimiter As String = "-") As Variant
' You can use this function in a subprocess that
' writes the values in the cells you want, or
' you can use it directly in the ouput cells
' Variables
Dim RemoveItems(2) As String
Dim Aux As Variant
' The variable RemoveItems is an array
' containing the characters you want to remove
RemoveItems(0) = "."
RemoveItems(1) = ","
RemoveItems(2) = " "
' STEP 1 - The variable Aux will store the text
' given as input
Aux = TextInput
' STEP 2 - Characters stored in the variable
' RemoveItems will be removed from Aux
For i = 0 To UBound(RemoveItems)
Aux = Replace(Aux, RemoveItems(i), "")
Next i
' STEP 3 - Once Aux is "clean", it will be
' transformed into an array containing the
' values separated by the delimiter
' As you can see at the function's header,
' Delimiter default value is "-". You can change
' it depending on the situation
Aux = Split(Aux, Delimiter)
' STEP 4 - The result of this function will be
' a numeric value. So, if the value of the
' selected position in Aux is not numeric it will
' remove the first character assuming it is a
' currency symbol.
' If something fails in the process the function
' will return "ERROR", so you can know you may
' verify the inputs or adjust this code for
' your needs.
On Error GoTo ErrHndl
If Not IsNumeric(Aux(Position)) Then
ExtractNumber = CLng(Mid(Aux(Position), 2))
Else
ExtractNumber = CLng(Aux(Position))
End If
Exit Function
ErrHndl:
ExtractNumber = "ERROR"
End Function
You can even do this with just worksheet formulas. Under certain circumstances, Excel will ignore the $ and ,. The double unary converts the returned string to a numeric value.
First Value: =--LEFT(A1,FIND("-",A1)-1)
Second Value: =--MID(A1,FIND("-",A1)+1,99)

VB.net read a text file and populate a combobox with specific extracted words

I have a problem which is giving me a headache. I really thought someone would have asked this already, but days of reading and testing has been fruitless.
I have a text file which starts:
"Determining profile based on KDBG search...
Suggested Profile(s) : WinXPSP2x86, WinXPSP3x86 (Instantiated with WinXPSP2x86)"
(The blank line between the two is not an error and neither are the spaces before 'Suggested')
I need to read the line starting 'Suggested...' only and extract every unique word starting 'Win' and populate a combobox with them. (i.e. 'WinXPSP2x86' and 'WinXPSP3x86')
I know i need to use the 'StreamReader' class and probably get a Regex going on, but, as a beginner, connecting it all together is beyond my knowledge at the moment.
Can anyone help? It would be much appreciated.
Imports System.IO
Public Class Form1
Private Sub Form1_Load( sender As Object, e As EventArgs) Handles MyBase.Load
' BASIC is case sensitive and e is parameter so we will start
' new variables with the letter f.
' Read all lines of file into string array F.
Dim F As String() = File.ReadAllLines("H:\Projects\35021241\Input.txt")
' F() is a 0 based array. Assign 3 line of file to G.
Dim G As String = F(2)
' On line 3 of file find starting position of the word 'win' and assign to H.
' TODO: If it is not found H will be -1 and we should quit.
Dim H As Integer = G.IndexOf("Win")
' Assign everything beginning at 'win' on line 3 to variable I.
Dim I As String = G.Substring(H)
' The value placed in delimiter will separate remaining values in I.
' Place C after ending quote to represent a single character as opposed to a string.
Dim Delimiter As Char = ","C
' J array will contain values left in line 3.
Dim J As String() = I.Split(Delimiter)
' Loop through J array removing anything in parenthesis.
For L = J.GetLowerBound(0) to J.GetUpperBound(0)
' Get location of open parenthesis.
Dim ParenBegin As Integer = J(L).IndexOf("(")
' If no open parenthesis found continue.
If ParenBegin <> -1 then
' Open parenthesis found. Find closing parenthesis location
' starting relative to first parenthesis.
Dim Temp As String = J(L).Substring(ParenBegin+1)
' Get location of ending parenthesis.
Dim ParenEnd As Integer = Temp.IndexOf(")")
' TODO: Likely an exception will be thrown if no ending parenthesis.
J(L) = J(L).Substring(0,ParenBegin) & J(L).Substring(ParenBegin + ParenEnd +2)
' Change to include text up to open parenthesis and after closing parenthesis.
End If
Next L
' UnwantedChars contains a list of characters that will be removed.
Dim UnwantedChars As String = ",()"""
' Check each value in J() for presence of each unwanted character.
For K As Integer = 0 to (UnwantedChars.Length-1)
For L = J.GetLowerBound(0) To J.GetUpperBound(0)
' Declare M here so scope will be valid at loop statement.
Dim M As Integer = 0
Do
' Assign M the location of the unwanted character or -1 if not found.
M= J(L).IndexOf(UnwantedChars.Substring(K,1))
' Was this unwanted character found in this value?
If M<>-1 Then
' Yes - where was it found in the value?
Select Case M
Case 0 ' Beginning of value
J(L) = J(L).Substring(1)
Case J(L).Length ' End of value.
J(L) = J(L).Substring(0,(M-1))
Case Else ' Somewhere in-between.
J(L) = J(L).Substring(0,M) & J(L).Substring(M+1)
End Select
Else
' No the unwanted character was not found in this value.
End If
Loop Until M=-1 ' Go see if there are more of this unwanted character in the value.
Next L ' Next value.
Next K ' Next unwanted character.
' Loop through all the values and trip spaces from beginning and end of each.
For L As Integer = J.GetLowerBound(0) To J.GetUpperBound(0)
J(L) = J(L).Trim
Next L
' Assign the J array to the combobox.
ComboBox1.DataSource = J
End Sub
End Class
As some have already suggested:
Use System.IO.File.ReadAllLines, if the file is not too big
Iterate through the array of lines
For each line, use the Split method to split on space
Check the first three characters of each word
This works but does of course need some error checking etc:
Dim lines() As String = System.IO.File.ReadAllLines("c:\temp\example.txt")
Dim lineWords() As String
For Each line As String In lines
lineWords = line.Split(New Char() {" "}, System.StringSplitOptions.RemoveEmptyEntries)
For Each word As String In lineWords
If word.Length > 3 Then
If word.Substring(0, 3).ToUpper = "WIN" Then
cmbWords.Items.Add(word)
End If
End If
Next
Next

replace space in a string at random position in vb.net

I want to select a random space in a string and replace it with a word (%word%) but there is a problem. The position cannot be fixed as i want it to be inserted at a random break. Few things which iam considering :
1)break the string at a space and merge it with the word
2) find a random space and replace it with the word. I like this point and so far all i have is break the selectedtext into string array and then iterate over each line. But i don't know how to find a random string position? Any short and sweet code please?
If (rtfArticle.SelectedText.Length > 0) Then
Dim strArray As String() = rtfArticle.SelectedText.Split(New Char() {ChrW(10)})
For Each str3 As String In strArray
If (str3.Contains(" ") = True) Then
End If
Next
End If
You could use the Random class to generate a random position index.
Dim testString = "This is just a test for random position"
Dim random = New Random()
Dim randomPos = random.Next(0, testString.Length - 1)
Debug.Print(String.Format("Char at Pos {0} = {1}", randomPos, testString.ElementAt(randomPos)))
You could locate the spaces in the string, pick one by random, and replace it. Something like:
' Get string
Dim data As String = rtfArticle.SelectedText
' Get space positions
Dim spaces As New List(Of Integer)
For i As Integer = 0 to data.Length - 1
If data(i) = " "C Then spaces.Add(i)
Next
' Get a random space
Dim rnd As New Random()
Dim pos As Integer = spaces(rnd.Next(spaces.Length))
' Remove the space
data = data.Remove(pos, 1)
' Insert the replacement
data = data.Insert(pos, "%word%")
' Put the string back
rtfArticle.SelectedText = data