vba to find word or phrase then highlight the entire paragraph that follows it - highlight

I've used the following code to find a key word or phrase then highlight the line -- but can't figure out how to make it highlight the entire paragraph and/ or list that follows it...
For example:
(ideally, highlighting this paragraph AND the list that provides further details would be best -but if only the paragraph is achievable, that's better than nothing):
"The Contractor shall turn in monthly status reports within ten business days after the end of each month. The report should include:
(a) Accomplishments
(b) Meetings and Outcomes
(c) Completed Travel and Purpose of Travel"
I've researched several commands and looked for examples but still at a loss as a novice. I tried "wdParagraph" but couldn't get that to work. Located refs of maybe using a "paragraph.range.select" and also found a note that advised these "start" and "end" terms (below) to select a paragraph.. but not sure how to achieve this? Hoping someone has an example of how to accomplish this as it will help greatly with quickly identifying hundreds of software reqs out of a 100 page word doc.. so frustrated!
* Selection.StartOf Unit:=wdParagraphm
* Selection.MoveEnd Unit:=wdParagraph
Sub Find_Highlight_Word_to_End_of_Line()
'BUT NEED IT TO HIGHLIGHT THROUGH END OF PARAGRAPH
'AND HIGHLIGHT LISTED ITEMS IF APPLICABLE
'LIKE THE LISTS IN THE EXAMPLE DOCUMENT
Dim sFindText As String
'Start from the top of the document
Selection.HomeKey wdStory
sFindText = "Contractor Shall"
Selection.Find.Execute sFindText
Do Until Selection.Find.Found = False
Selection.EndKey Unit:=wdLine, Extend:=wdExtend
Selection.Range.HighlightColorIndex = wdYellow
Selection.MoveRight
Selection.Find.Execute
Loop
End Sub

A couple of awesome experts shared 2 methods with me to achieve the full paragraph highlighting I needed.. Hope these help others! Fascinating to see different ways to achieve the same result!
Method 2 Code (Alternative) is shorter:
Sub Highlight_Paragraph()
Dim oRng As Range
Set oRng = ActiveDocument.Range
With oRng.Find
Do While .Execute(FindText:="Contractor Shall")
oRng.Paragraphs(1).Range.HighlightColorIndex = wdYellow
oRng.Collapse 0
Loop
End With
lbl_Exit:
Set oRng = Nothing
Exit Sub
End Sub
Method 1 Code (MatchWildcards=False):
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "Contractor Shall"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = True
.MatchWildcards = False
.Execute
End With
Do While .Find.Found
.Duplicate.Paragraphs.First.Range.HighlightColorIndex = wdYellow
.Start = .Duplicate.Paragraphs.First.Range.End
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
End Sub

Related

Lua - How to ignore a result from a table iteration without removing it?

I wanto to create a crossword puzzles's solver with Lua. I'm not used to this language tho and my english is poor, sorry for that.
I have to iterate multiples times the same table of tables checking if the given word is present or not and, if present, replace every char of that word in the table with a "*" simbol.
For example:
schema= {
{"A","B","C","D","H","F","G","W","T","Y"},
{"U","H","E","L","L","O","I","I","O","L"},
{"G","F","D","R","Y","T","R","G","R","R"}}
function(schema,"HELLO")
schema= {
{"A","B","C","D","H","F","G","W","T","Y"},
{"U","*","*","*","*","*","I","I","O","L"},
{"G","F","D","R","Y","T","R","G","R","R"}}
For now i'm focusing on find the word scanning the table from left to right. Here's my code:
i = 1
t = {}
for k,w in pairs(schema) do
t[k] = w
end
cercaPrima = function(tabella,stringa)
for v = 1, 10 do
if string.sub(stringa,1,1) == t[i][v] then
print(t[i][v]) v = v+1
return cercaDS(t,stringa,i,v)
else
v = v+1
end
end
if i < #t then
i = i+1
cercaPrima(tabella,stringa)
else
return print("?")
end
end
cercaDS = function(tabella,stringa,d,s)
local o = 2
local l = 2
while o <= #stringa do
if string.sub(stringa,o,l) == tabella[d][s] then
print(tabella[d][s])
tabella[d][s] = "*"
s=s+1
o=o+1
l=l+1
else
l=l-1
s=s-l
o=#stringa+1
tabella[d][s] = "*"
return cercaPrima(tabella,stringa)
end
end
end
cercaPrima(schema,"HELLO")
It's probably overcomplicated, but my question is: How can I make it ignore the first "H" (not turning it into a "*") while keep iterating the table looking for another "H" who fits the criteria?
My goal is to create a function who takes a table and a list of words in input, iterates the table looking for every single word, if it finds them all it replaces every char of every word found in the table with a "*" and print the remaining characters as a string.
Another problem that i'll probabily have is: what if a char of a word is a char of another word too? It will read "*" instead of the real char if it has already found the first word.
Should I create a new table for every word I'm looking for? But then how can i merge those table togheter to extrapolate the remaining characters?
Thank you for your help!
If you want to ignore something one time you can use a conditional statement. Just remember that you encountered it already using a variable. But I don't see how this makes sense here.
A problem like this is probably solved better by turing each line and column into strings and then stimply search the strings for words.
I find string.gsub() is a great find and replacement tool.
Maybe it hit not all requirements but maybe it inspire you.
> function cercaPrisma(tab,txt) for i=1,#tab do print((table.concat(tab[i]):gsub(txt, ('*'):rep(txt:len())))) end end
> cercaPrisma(schema, 'HELLO')
ABCDHFGWTY
U*****IIOL
GFDRYTRGRR
> cercaPrisma(schema, 'DRY')
ABCDHFGWTY
UHELLOIIOL
GF***TRGRR

how to insert keyword in the step load definition section using python script?

I am using python to insert *Include, Input=file.inp into step load definition section to apply for pressure boundary condition on nodes. Here is my script, however, it is inserted in Part level section. I am wondering how to control the insert position using python. Thanks
def GetKeywordPosition(myModel, blockPrefix, occurrence=1):
if blockPrefix == '':
return len(myModel.keywordBlock.sieBlocks)+1
pos = 0
foundCount = 0
for block in myModel.keywordBlock.sieBlocks:
if string.lower(block[0:len(blockPrefix)])==\
string.lower(blockPrefix):
foundCount = foundCount + 1
if foundCount >= occurrence:
return pos
pos=pos+1
return +1
position = GetKeywordPosition(myModel, '*step')+24
myModel.keywordBlock.synchVersions(storeNodesAndElements=False)
myModel.keywordBlock.insert(position, "\n*INCLUDE, INPUT=file.inp")
You can adapt the re module. This should work
import re
# Get keywordBlock object
kw_block = myModel.keywordBlock
kw_block.synchVersions(storeNodesAndElements=False)
sie_blocks = kw_block.sieBlocks
# Define keywords for the search (don't forget to exclude special symbols with '\')
kw_list = ['\*Step, name="My Step"']
# Find index
idx = 0
for kw in kw_list:
r = re.compile(kw)
full_str = filter(r.match, sie_blocks[idx:])[0]
idx += sie_blocks[idx:].index(full_str)
UPD: Some explanations as requested
As keywords in the .inp file could be somewhat repetitive, the main idea here is to create a "search route", where the last pattern in the list will correspond to a place where you want to make your modifications (for example, if you want to find the "*End" keyword after a specific "*Instance" keyword).
So we proceed iteratively through our "search route" == list of search patterns:
Compile the regex expression;
Find the first appearance of the pattern in the sie_blocks starting from the index idx;
Update the idx so the next search is performed from this point.
Hope this will help

How to count the number of noun appeared in a paragraph with Google's NL api using ruby?

Trying to count the number of noun appeared in a paragraph with Google's NL api using ruby.
Been looking up the document, couldn't find how to do this.
Work out a solution last night
text = 'xxxxxxxxxx'
response = language.analyze_syntax content: text, type: :PLAIN_TEXT
sentences = response.sentences
tokens = response.tokens
x= tokens.count
a = Array.new(x-1)
for i in 1..x
a[i-1] = tokens[i-1].part_of_speech.tag.to_s
end
for i in 1..x
if a[i-1] == 'NOUN'
num= num+1
end
end
still wondering if there exist something like (tokens.noun.count ?) in the nl api https://cloud.google.com/natural-language/docs/analyzing-syntax#language-syntax-string-ruby.
Building on your example, you could count the number of NOUNs like so:
text = 'xxxxxxxxxx'
response = language.analyze_syntax content: text, type: :PLAIN_TEXT
tokens = response.tokens
tokens.count { |t| t.part_of_speech.tag.to_s == 'NOUN' }
Note that in ruby, it is very common style to use iterators like this, rather than defining temporary variables and using for loops. (In fact, you should almost never find a need to use for loops in ruby!)
This clean, concise syntax is one of the biggest appeals of the ruby language. Very often, you can obtain a desired result in one line of code like that rather than all of this temporary array and index counter declarations.

Lua - generate sequence of numbers

How do I generate a sequence of integer numbers based on first and last number for for to loop over?
The following pseudocode
for i in sequence(4,9) do
print(i)
end
should produce the following output
4
5
6
7
8
9
Please include a short explanation what the solution does in the background and what terminology would have allowed one to find the solution.
Search attempts lead to unsearchable huge pages of documentation.
You can use numeric for loop to do that. You will find details in Programming in Lua section I referenced or the Lua manual section on For statement.
Just for the full record, there are basically 3 ways you could do this loop, one with a slightly different syntax, and 2 with the exact syntax as your pseudocode. Links point to relevant chapters in Programming in Lua (which is a great book to read, by the way).
1) Using a simple numeric for loop - in this case you won't use sequence:
for i=4,9 do
print(i)
end
2) Implement sequence as a closure:
function sequence(from,to)
local i = from - 1
return function()
if i < to then
i = i + 1
return i
end
end
end
for i in sequence(4,9) do print(i) end
3) Implement sequence as a coroutine:
function sequence(from, to)
return coroutine.wrap(function()
for i=from,to do
coroutine.yield(i)
end
end)
end
for i in sequence(4,9) do print(i) end

Wiki-fying a text using LPeg

Long story coming up, but I'll try to keep it brief. I have many pure-text paragraphs which I extract from a system and re-output in wiki format so that the copying of said data is not such an arduous task. This all goes really well, except that there are no automatic references being generated for the 'topics' we have pages for, which end up needing to be added by reading through all the text and adding it in manually by changing Topic to [[Topic]].
First requirement: each topic is only to be made clickable once, which is the first occurrence. Otherwise, it would become a really spammy linkfest, which would detract from readability. To avoid issues with topics that start with the same words
Second requirement: overlapping topic names should be handled in such a way that the most 'precise' topic gets the link, and in later occurrences, the less precise topics do not get linked, since they're likely not correct.
Example:
topics = { "Project", "Mary", "Mr. Moore", "Project Omega"}
input = "Mary and Mr. Moore work together on Project Omega. Mr. Moore hates both Mary and Project Omega, but Mary simply loves the Project."
output = function_to_be_written(input)
-- "[[Mary]] and [[Mr. Moore]] work together on [[Project Omega]]. Mr. Moore hates both Mary and Project Omega, but Mary simply loves the [[Project]]."
Now, I quickly figured out a simple or complicated string.gsub() could not get me what I need to satisfy the second requirement, as it provides no way to say 'Consider this match as if it did not happen - I want you to backtrack further'. I need the engine to do something akin to:
input = "abc def ghi"
-- Looping over the input would, in this order, match the following strings:
-- 1) abc def ghi
-- 2) abc def
-- 3) abc
-- 4) def ghi
-- 5) def
-- 6) ghi
Once a string matches an actual topic and has not been replaced before by its wikified version, it is replaced. If this topic has been replaced by a wikified version before, don't replace, but simply continue the matching at the end of the topic. (So for a topic "abc def", it would test "ghi" next in both cases.)
Thus I arrive at LPeg. I have read up on it, played with it, but it is considerably complex, and while I think I need to use lpeg.Cmt and lpeg.Cs somehow, I am unable to mix the two properly to make what I want to do work. I am refraining from posting my practice attempts as they are of miserable quality and probably more likely to confuse anyone than assist in clarifying my problem.
(Why do I want to use a PEG instead of writing a triple-nested loop myself? Because I don't want to, and it is a great excuse to learn PEGs.. except that I am in over my head a bit. Unless it is not possible with LPeg, the first is not an option.)
So... I got bored and needed something to do:
topics = { "Project", "Mary", "Mr. Moore", "Project Omega"}
pcall ( require , 'luarocks.require' )
require 'lpeg'
local locale = lpeg.locale ( )
local endofstring = -lpeg.P(1)
local endoftoken = (locale.space+locale.punct)^1
table.sort ( topics , function ( a , b ) return #a > #b end ) -- Sort by word length (longest first)
local topicpattern = lpeg.P ( false )
for i = 1, #topics do
topicpattern = topicpattern + topics [ i ]
end
function wikify ( input )
local topicsleft = { }
for i = 1 , #topics do
topicsleft [ topics [ i ] ] = true
end
local makelink = function ( topic )
if topicsleft [ topic ] then
topicsleft [ topic ] = nil
return "[[" .. topic .. "]]"
else
return topic
end
end
local patt = lpeg.Ct (
(
lpeg.Cs ( ( topicpattern / makelink ) )* #(-locale.alnum+endofstring) -- Match topics followed by something thats not alphanumeric
+ lpeg.C ( ( lpeg.P ( 1 ) - endoftoken )^0 * endoftoken ) -- Skip tokens that aren't topics
)^0 * endofstring -- Match adfinum until end of string
)
return table.concat ( patt:match ( input ) )
end
print(wikify("Mary and Mr. Moore work together on Project Omega. Mr. Moore hates both Mary and Project Omega, but Mary simply loves the Project.")..'"')
print(wikify("Mary and Mr. Moore work on Project Omegality. Mr. Moore hates Mary and Project Omega, but Mary loves the Projectaaa.")..'"')
I start off my making a pattern which matches all the different topics; we want to match the longest topics first, so sort the table by word length from longest to shortest.
Now we need to make a list of the topics we haven't seen in the current input.
makelink quotes/links the topic if we haven't seen it already, otherwise leaves it be.
Now for the actual lpeg stuff:
lpeg.Ct packs all our captures into a table (to be concated together for output)
topicpattern / makelink captures a topic, and passes in through our makelink function.
lpeg.Cs substitutes the result of makelink back in where the match of the topic was.
+ lpeg.C ( ( lpeg.P ( 1 ) - locale.space )^0 * locale.space^1 ) if we didn't match a topic, skip a word (that is, not spaces followed by a space)
^0 repeat.
Hope thats what you wanted :)
Daurn
Note: Edited code, description no longer correct
So why don't you use string.find? It search only for a first topic occurrence and gives you its starting index and length. All you have to do is to add '[[' to a result.
For each chunk, copy the topics table and when the first occurency has been found, remove it.
Sort topics by length, most long first so that the most relevant topic will be found first
LPeg is a good tool, but it's not necessary to use it here.

Resources