I'm new to DXL and I want to extract the variables containing
_I_,_O_ and _IO_
from a module and export then to csv file. Please help me with this
EG:
ADCD_WE_I_DFGJDGFJ_12_QWE and CVFDFH_AWEQ_I_EHH[X] is set to some value
This question has two parts.
You want to find variables that contain those parts in their name
You want to export to a .csv file
Another person may be able to expand on a better way, but the only way coming to mind right now for 1. is this:
Loop over the attributes in the module (for ad in m do {}) and get the string of the attribute names.
I am assuming that your attributes are valued at _I_, _O_ or _OI_? Like alpha = "_I_"? Are these enumerate values?
If they are, then you only need to check the value of each object's attribute. If one of those are the attribute values, then add it to something like a skip list. Having a counter here would be useful, maybe one for each attribute, like countI, countO, countOI, you can then use the counters as keys for the put() function for the skip list.
Once you have found all the attributes then you can move on to writing to csv
Stream out = write("filepathname/filename.csv") // to declare the stream
out << "_I_, _O_, _OI_\n"
Then you could loop over your Skip lists at the same time
int ijk = 0; bool finito = false
while(!finito) do {
if(ijk<countI) {
at = get(skipListI, ijk)
out << at.name ","
}
else out << ","
if(ijk<countO) {
at = get(skipListO, ijk)
out << at.name ","
}
else out << ","
if(ijk<countOI) {
at = get(skipListOI, ijk)
out << at.name "\n"
}
else out << "\n"
ijk++
// check if the next iteration would be outside of bounds on all lists
if(ijk >= countI && ijk >= countO && ijk >= countIO) finito = true
}
Or instead of at.name, you could print out whatever part of the attribute you wanted. The name, the value, "name:value" or whatever.
I have not run this, so you will be left to do any troubleshooting.
--
I hope this idea gets you started, write out what you want on paper first and then follow that plan. The key things I have mentioned that would be useful here are Skip lists, and Stream write (or append, if you want to keep adding).
In the future, please consider making your question more clear. Are you looking for those search terms in the name of the attribute, or in the value of the attribute. Are you looking to print out the names or the values, or the what? What kind of format for the .csv are you going to have? Any information will help your question be answered.
Related
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
Basically, I have to go through all baselines of an object until I get the author who modified "_ReqStatus" attribute and copy that value in "_Ownr" attribute. Everything is working fine for the current baseline, but I cannot get through the older baselines of the module. I have to mention that I run the script for 2000 objects each one having at least 20 baselines.
My code looks like this:
//scriptul recunoaste obiectele cu "ReqStatus modifica"
pragma runLim, 0
Module m = current
History h
HistoryType ht
Object o
string attributName
string attributNameBaseline
string authorName
string newOwner
Baseline lBaseLine
noError()
for o in entire m do {
**for lBaseLine in module(o) do{ //These 2 code lines were my try to load all baselines
Module lBaseMod = load(module(o), false) //but with no results**
for h in o do
{
string owner = ""
attributName=""
attributName = h.attrName
authorName=""
owner = o."_Owner"
if isDeleted(o) then continue
if(attributName=="_ReqStatus")
{
authorName=h.author
//print authorName
//print "\n"
if(null owner)
{
print identifier(o)
print "\n"
newOwner = authorName
print newOwner"\n"
o."_Ownr" = newOwner
//print newOwner
break
}
}
}
}
}
ErrMess = lastError()
Thanks
Tony Goodman provides a script "Smart History Viewer" at http://www.smartdxl.com/content/?p=418, Michael Sutherland has one at https://www.ibm.com/mysupport/s/forumsquestion?id=0D50z00006HIGSUCA5, also, if you do a search on https://www.ibm.com/mysupport/s/forumshome for e.g. "dxl history" you might find some more code examples which should help you with this topic.
Your problem is the variable o. It is set only in the loop for o in entire m, it always refers to the o in the current version of m, never to the corresponding Object in a baseline. When you open the Module lBaseMod, o is not automatically reassigned.
So, use a new variable of type Object, set it to the Object in the baseline corresponding to o and browse through this new Object's history, see the linked scripts for reference.
Also, you should rework the flow of your script. With your approach, you open all the Baselines of m for each Object. In your case this means 2000 * 20 load and close. It will be much faster (though not necessarily less memory consuming) to open all the baselines of m in an outer loop, probably using a Skip list to collect the necessary information.
Also note that when you test your script, "print" becomes very slow after some time. It will be faster if you remember all the values that you want to print e.g. in a Buffer and print it at the end of your script, or write the output to a file.
I want to find specified text within a string in a given column, and count how many times that string is repeated throughout the entire column.
For example, Find "XX" within a string in a column and print to dialogue box the number of times that text was found.
Module m = current
Object o
string s
string x
int offset = null
int len = null
int c
for o in m do
{
string s = probeAttr_(o, "AttributeA")
x = o."Object Text" ""
if(findPlainText(s, "XX", offset, len, false)){
print "Success "
} else {
print "Failed to match"
}
}
I have tried to use command findPlainText but I am inadvertently passing every object as true.
As well I placed the output to print 'success' or 'Failed to match' so I can at least get a number count of what is being passed. Unfortunately it seems like everything is being passed!
My understanding is that 'probeAttr_(o, "AttributeA")' allows me to specify and enter what column to search. As well o."Object Text" "" now allows me to look within any object and search for any text contained. I also realize that variable x is not being used but assume it has some way of being used to solve this issue.
I only use DOORS at a surface level but having this ability will save other staff tons of time. I realize this may be accomplished using the DOORS advanced filtering capability but I'd be able to compound this code with other simple commands to save time.
Thank you in advance for your help!!
If you want to count every occurence of a specified string in a text in an attribute for all objects, I think Mike's proposal is the correct answer. If you are only interested, if the specified string occurs once in that object's attribute, I suggest using Regexp, as I find it very fast, quite powerful and nevertheless easy to use, e.g.:
Regexp reSearch = regexp2 "XX"
int iCounter = 0
string strOT = ""
for o in m do {
strOT = o."Object Text" ""
if (reSearch strOT) {
iCounter++
}
}
print "Counted: '" iCounter "'\n"
Most of this has been answered in (DXL/Doors) How to find and count a text in a string?
You can easily exchange the "print" with a counter.
I have created a DXL script that goes through every row of a couple modules. I am printing out certain rows and its information. I am doing this by having a for loop that goes through the rows and if it hits a row that I am interested in, I save the elements in the columns of this row to different string variables and print those string variables. The script does not take too long to run if the module does not have a lot of rows I am interested in but if I want to run multiple modules at the same time or if a module has a lot of rows I am interested in, the script can take hours. I can show the code that I have if this is not enough to come up with solutions. Any help would be appreciated!
I have tried using a skip list to store the print statements in that and then tried going through the skip list to print each value but that did not make the script run any faster.
string sep=","
for o in m do
{
string ver1= o."column1"
if (checkIf(o) && (!(isDeleted(o))))
{
string ver2= o."column2"
string onum=number(o)
""
string otext = o."Object Text"
print ver1 sep ver2 sep onum
}
}
Initial optimization:
for o in m do
{
if (checkIf(o) && (!(isDeleted(o)))) {
//This doesn't appear to be used?
//string otext = o."Object Text"
print o."column1" "," o."column2" "," number(o) "\n"
}
}
Reasoning: DOORS has a system in place called the string table that holds declared strings in memory- and doesn't necessarily do the best at clearing it out when appropriate. By constantly declaring strings in your loop, you might be bumping into the memory limits of that system.
Problem with this is that the results all end up in that 'DXL editor' little window, and then have to be copy and pasted somewhere else to actually use it.
Secondary optimization:
// Turn off runlimit for timing
pragma runLim , 0
// Set file location - CHANGE FOR YOUR COMPUTER
string csv_location = "C:/Users/Username/Desktop/Info_Collection.csv"
// Open stream
Stream out = append csv_location
// Set headers
out << "Module,Column 1,Column 2,Object Number" "\n"
// Define your loop constraints
Module m = current
Object o
// Run your loop
for o in m do
{
if (checkIf(o) && (!(isDeleted(o)))) {
//This doesn't appear to be used?
//string otext = o."Object Text"
out << fullName(m)","o."column1" "," o."column2" "," number(o) "\n"
}
}
close out
This will let you run the same script in different modules, all outputting to the same CSV file, which you can then load into Excel or your data manipulation engine of choice.
This keeps the data collection happening outside of DOORS, so if something goes awry, you can track down where it occurred.
My third optimization would be to use a list of modules in, say, excel as an input and do this analysis, but that might be going too far.
If this doesn't help, then we can start examining other issues.
Note- I still would like to know what 'checkIf' is/does.
If your objective is to speed up the execution of the script, since most of the objects are of no interest to you, the most effective way I know of is to filter out most of the objects that are not interesting, e.g., a filter which is obj."Object Text" != "" would filter out Headings, if you are just interested in requirements, obj."Object Text" contains "[Ss]hall" etc. Save as a view for later use.
for o in m do { respects the display set, so if you don't touch most of the objects it will speed it up a lot!
Hope this helps.
Don
I am attempting to make a Lua script for an online community I am a part of, I am having a problem when I attempt to search through a table array I believe. It doesn't detect the results I want.
The way it is supposed to work is that when someone types /gps [streetname] it will search the table at the top, detect the matching streetname & the coordinates and then set a waypoint to that relevant position.
At the moment it works when there is just one entry in the table, but when I put more, it will provide the error message for any non-matching streets & then the waypoint set message for the matching streets. I've Googled and don't appear to be able to find anything to help.
Any help would be appreciated.
waypoint = {
{404.08, -920.23, 'sinnerstreet', 'Sinner Street'},
{360.85, -956.46, 'atleestreet', 'Atlee Street'},
{500.48, -956.80, 'littlebighornavenue', 'Little Bighorn Avenue'},
}
RegisterCommand('gps', function(source, args, rawCommand)
for k,v in pairs(waypoint) do
x, y, streetname, displayname = table.unpack(v)
results = ""
if args[1] == nil then
if IsWaypointActive() then
SetWaypointOff()
TriggerEvent('chatMessage', '^1^*GPS Navigation: ^r^7Your GPS system has been reset.')
return end
elseif args[2] == nil and args[3] == nil then
results = args[1]
elseif args[2] ~= nil and args[3] == nil then
results = args[1] .. args[2]
else
results = args[1] .. args[2] .. args[3]
end
results = string.lower(results) -- This convertes the args into lower case
end
-- This locates the streetname and sets a waypoint to it for the player
if string.find(streetname, results) then
SetNewWaypoint(x, y)
TriggerEvent('chatMessage', '^1^*GPS Navigation: ^r^7Your waypoint to ^1' .. displayname .. '^r^7 has been set.')
else
TriggerEvent('chatMessage', '^1^*GPS Navigation: ^r^7There has been an error with your street name, please try again.')
end
end)
TriggerEvent('chat:addSuggestion', '/gps', 'This creates a waypoint to your designated street. ^*USE: /gps [streetname]')
To be honest, your code makes little to no sense, and it's probably because you're not using all the nice stuff Lua has to offer.
{404.08, -920.23, 'sinnerstreet', 'Sinner Street'},
You're storing redundant data there. The third value is really just the fourth one with spaces removed and all lowercase.
'sinnerstreet' == ('Sinner Street'):gsub("[^%l]", ""):lower()
In english: take "Sinner Street", globally (meaning in the entire string) substitute everything that is not a lowercase (%l) letter with nothing (""), then make the result of that lowercase. What you get is "sinnerstreet".
x, y, streetname, displayname = table.unpack(v)
Using globals there, that's not good. Globals are the devil. Don't use them.
Then, a few lines further down:
SetNewWaypoint(x, y)
Think about it for a moment. You set x and y in each iteration of your for loop. After the loop is done, they always contain the coordinates of the last waypoint you iterated over. I doubt that's what you want. Use local; it forces you to think what you want the scope of your variables to be, which will help you spot this kind of problem.
elseif args[2] ~= nil and args[3] == nil then
results = args[1] .. args[2]
Unless you specifically want to limit it to 3 arguments, which I doubt, you can also use table.concat to concatenate all the values in a sequence (read: array)
results = string.lower( table.concat(args) )
The thing that puzzles me is why you do this in a loop. For every waypoint, you set result to the same value, which is all the arguments concatenated and converted to lower case.
now what though? You check if result (what the user searched for) contains streetname, which, as we have previously found out, contains the name of the last waypoint in the list.
Using tables for searching
Lua has tables, one of if not the most powerful general-purpose data structure in programming.
local map = {}
for _,waypoint in ipairs(waypoints) do
map[waypoint[3]:lower()] = waypoint
end
This will get you something that looks about like this:
local map = {
sinnerstreet = {404.08, -920.23, 'sinnerstreet', 'Sinner Street'},
atleestreet = {360.85, -956.46, 'atleestreet', 'Atlee Street'},
littlebighornavenue ={500.48, -956.80, 'littlebighornavenue', 'Little Bighorn Avenue'},
}
and if you want to know if a street exists, you can just do this:
if map['atleestreet'] then
print(map.atleestreet[4])
end
if treats everything that isn't false or nil as truthy, so you can just write `map['atleestreet'] in the condition
my_table['text'] can be written as my_table.text
Looking up string indices in a table is pretty fast because of how it's implemented.
Conclusion
Try thinking your code through. If necessary, go through it line by line, writing down what values the variables hold in each moment. If you've been at it for a while, get some rest first or do something else for a while.
Then set your variables to local wherever possible (read: everywhere), figure out what needs to be inside and outside the loop and try again.
Remarks
Instead of if something == nil you can just write if not something, and if something ~= nil just if something
Apologies
Sorry for the long wall of text and using spaces inside brackets, but I wanted things to be specially easy to understand.