Address Summary Report.fh_lua--[[
@Title: Address Summary Report
@Author: Peter Richmond
@LastUpdated: 06Mar2012
@Version: 1.3
@Description: Counts and Lists All Addresses in the File.
Similar to FH Standard report "Data - Addresses" but:
(a) Each Address (including multi-line) is shown on a single line.
(b) Leading numbers can be either sorted numerically or ignored for primary sort.
(c) Count is to the left of the Address.
(d) (V1.1) Option to append relevant Place (if present) to each Address.
(e) (V1.2) Option to sort and display Address (and Place if appended) with Parts reversed.
(V1.3) Number handling improved and a bug fixed.
]]
require("iuplua")
-- Dialog for user to specify required sortation.
sTitle = "Address Summary Report"
sOption1 = "Leading Numbers Numerically"
sOption2 = "Ignore Leading Numbers"
sOption3 = "Address Parts Reversed"
iOption = 0
iPlace = 0
bOK, iOption, iPlace = iup.GetParam(sTitle, param_action,
"Please specify required sortation: %o|"..sOption1.."|"..sOption2.."|"..sOption3.."|\n" ..
"Append Place (if present) to Address?: %b[No,Yes]\n",
iOption, iPlace)
if bOK then
if iOption == 0 then
iNsort = 1
iAsort = 2
sSubtitle = sOption1
else
iNsort = 2
iAsort = 1
sSubtitle = sOption2
end
tTypes = {"INDI","FAM","REPO","SUBM"} -- Record Types that may contain ADDR tags
tAddresses = {} -- Define array for Addresss
pi = fhNewItemPtr() -- declare pointer
pi2 = fhNewItemPtr() -- declare pointer
for iType,sTypeDesc in ipairs(tTypes) do -- Scan the four Record Types
pi:MoveToFirstRecord(sTypeDesc)
while pi:IsNotNull() do
sType = fhGetTag(pi)
if sType == 'ADDR' then
sAddr = fhGetValueAsText(pi)
if (sAddr ~= nil) and (sAddr ~= "") then -- Process a non-blank Address
sResult = string.gsub(sAddr, ",?\n", string.char(7)) -- Blob for newline
if iPlace == 1 then -- Append Place to Address
pi:MoveToParentItem(pi) -- i.e. Fact for current Address
pi2:MoveTo(pi,"~.PLAC") -- i.e. Place for current Fact
sPlac = fhGetValueAsText(pi2)
if (sPlac ~= nil) and (sPlac ~= "") then
sResult = sResult .. " " .. string.char(8) .. " " .. sPlac
end
pi:MoveNext()
if pi:IsNull() then -- Avoid premature termination of loop
pi:MoveToRecordItem(pi2)
pi:MoveNext()
end
end
-- Add the Address Result to the list
if (tAddresses[sResult] == nil) then
tAddresses[sResult] = 1
else
tAddresses[sResult] = tAddresses[sResult] + 1
end
end
end
pi:MoveNextSpecial()
end
end
-- Build Tables for the result set columns for Address and Count
tAddress = {}
tCount = {}
tNumber = {}
tRest = {}
tSortNum = {}
ii = 0 -- line counter for result tables
iMax = 40 -- inital (minimum) value for length of Address
iMax2 = 5 -- inital (minimum) value for length of Number
for sAddress, iCount in pairs(tAddresses) do
ii = ii + 1
tCount[ii] = iCount
-- Separate any leading Number from Rest of Address:
sNumber, iNumber, sPre, sRest = string.match(sAddress, "^(%p*(%d+)[^%c%s]*[ %p%d]*)%s+(%W*)(.*)")
if sNumber == nil then
sNumber = ""
end
sNumEnd = string.sub(sNumber, -2) -- move ordinals from Number to Rest of Address
if (sNumEnd == "st") or (sNumEnd == "nd") or (sNumEnd == "rd") or (sNumEnd == "th") then
sRest = sNumber .. " " .. sRest
sNumber = ""
iNumber = 0
end
sNumber = string.gsub(sNumber, "&", "&&") -- ensure ampersand displays OK
if iNumber == nil then
iNumber = 0
sPre, sRest = string.match(sAddress, "^(%W*)(.*)")
end
if iOption == 2 then -- Reverse the order of Address (& Place) parts
tPart = {} -- Table for Parts of Address ( & Place)
tSep = {} -- Table for Separators between Parts
iParts = 0 -- Count of Parts
iSeps = 0 -- Count of Separators
for sPart in string.gmatch(sAddress, "[^,%c]+") do
iParts = iParts + 1
if sPart == nil then sPart = "" end
tPart[iParts] = string.match(sPart, "^%s*(.*)%s*$")
end
for sSep in string.gmatch(sAddress, "[,%c]+") do
iSeps = iSeps + 1
tSep[iSeps] = sSep
end
while iParts - iSeps <= 0 do -- ensure 1 more Parts than Separators
iParts = iParts + 1
tPart[iParts] = ""
end
sRev = tPart[iParts] -- Start with last Part of Address (& Place)
while iSeps > 0 do -- Process Separators and Parts in reverse order
iParts = iParts - 1
sRev = sRev .. tSep[iSeps] .. tPart[iParts]
iSeps = iSeps - 1
end
sRev = string.gsub(sRev, ",", ", ")
-- Reverse sRest for sorting
sRevRest = ""
for sPart in string.gmatch(sRest, "[^,%c]+") do
if sPart == nil then sPart = "" end
sPart = string.match(sPart, "^%s*(.*)%s*$")
sRevRest = sPart .. ", " .. sRevRest
end
end
-- Populate output Tables:
tSortNum[ii] = string.format("%10u", iNumber)
if iOption ~= 2 then
tRest[ii] = ' ' .. sRest -- having removed non-alphabetic prefix for sorting
tNumber[ii] = sNumber
tAddress[ii] = ' ' .. string.gsub(sPre .. sRest, string.char(8), " " .. string.char(133) .. " ")
iLen2 = string.len(tNumber[ii])
if iLen2 > iMax2 then -- Sets maximum address length
iMax2 = iLen2
end
else
tRest[ii] = ' ' .. sRevRest
tAddress[ii] = ' ' .. string.gsub(sRev, string.char(8), " " .. string.char(133) .. " ")
end
iLen = string.len(tAddress[ii])
if iLen > iMax then -- Sets maximum address length
iMax = iLen
end
end
sAddCol = " Address"
if iPlace == 1 then
sAddCol = sAddCol .. " " .. string.char(133) .. " Place"
sSubtitle = sSubtitle .. " (with Place appended)"
end
if iOption == 2 then
sAddCol = sAddCol .. " - Reversed"
sSubtitle = sSubtitle .. " - Reversed"
end
iWid = 4 * iMax -- Sets Address column width
iWid2 = 4 * iMax2 -- Sets Number column width
fhOutputResultSetTitles(sTitle, sTitle, sSubtitle .. " %#c")
fhOutputResultSetColumn('Count', 'integer', tCount, ii, 24, 'align_right')
if iOption ~= 2 then
fhOutputResultSetColumn('No.', 'text', tNumber, ii, iWid2, 'align_right')
end
fhOutputResultSetColumn(sAddCol, 'text', tAddress, ii, iWid, 'align_left')
fhOutputResultSetColumn('', 'text', tRest, ii, 1, 'align_left', iAsort) -- Only for sorting
fhOutputResultSetColumn('', 'text', tSortNum, ii, 1, 'align_right', iNsort) -- Only for sorting
end
--[[
@Title: Address Summary Report
@Author: Peter Richmond
@LastUpdated: 06Mar2012
@Version: 1.3
@Description: Counts and Lists All Addresses in the File.
Similar to FH Standard report "Data - Addresses" but:
(a) Each Address (including multi-line) is shown on a single line.
(b) Leading numbers can be either sorted numerically or ignored for primary sort.
(c) Count is to the left of the Address.
(d) (V1.1) Option to append relevant Place (if present) to each Address.
(e) (V1.2) Option to sort and display Address (and Place if appended) with Parts reversed.
(V1.3) Number handling improved and a bug fixed.
]]
require("iuplua")
-- Dialog for user to specify required sortation.
sTitle = "Address Summary Report"
sOption1 = "Leading Numbers Numerically"
sOption2 = "Ignore Leading Numbers"
sOption3 = "Address Parts Reversed"
iOption = 0
iPlace = 0
bOK, iOption, iPlace = iup.GetParam(sTitle, param_action,
"Please specify required sortation: %o|"..sOption1.."|"..sOption2.."|"..sOption3.."|\n" ..
"Append Place (if present) to Address?: %b[No,Yes]\n",
iOption, iPlace)
if bOK then
if iOption == 0 then
iNsort = 1
iAsort = 2
sSubtitle = sOption1
else
iNsort = 2
iAsort = 1
sSubtitle = sOption2
end
tTypes = {"INDI","FAM","REPO","SUBM"} -- Record Types that may contain ADDR tags
tAddresses = {} -- Define array for Addresss
pi = fhNewItemPtr() -- declare pointer
pi2 = fhNewItemPtr() -- declare pointer
for iType,sTypeDesc in ipairs(tTypes) do -- Scan the four Record Types
pi:MoveToFirstRecord(sTypeDesc)
while pi:IsNotNull() do
sType = fhGetTag(pi)
if sType == 'ADDR' then
sAddr = fhGetValueAsText(pi)
if (sAddr ~= nil) and (sAddr ~= "") then -- Process a non-blank Address
sResult = string.gsub(sAddr, ",?\n", string.char(7)) -- Blob for newline
if iPlace == 1 then -- Append Place to Address
pi:MoveToParentItem(pi) -- i.e. Fact for current Address
pi2:MoveTo(pi,"~.PLAC") -- i.e. Place for current Fact
sPlac = fhGetValueAsText(pi2)
if (sPlac ~= nil) and (sPlac ~= "") then
sResult = sResult .. " " .. string.char(8) .. " " .. sPlac
end
pi:MoveNext()
if pi:IsNull() then -- Avoid premature termination of loop
pi:MoveToRecordItem(pi2)
pi:MoveNext()
end
end
-- Add the Address Result to the list
if (tAddresses[sResult] == nil) then
tAddresses[sResult] = 1
else
tAddresses[sResult] = tAddresses[sResult] + 1
end
end
end
pi:MoveNextSpecial()
end
end
-- Build Tables for the result set columns for Address and Count
tAddress = {}
tCount = {}
tNumber = {}
tRest = {}
tSortNum = {}
ii = 0 -- line counter for result tables
iMax = 40 -- inital (minimum) value for length of Address
iMax2 = 5 -- inital (minimum) value for length of Number
for sAddress, iCount in pairs(tAddresses) do
ii = ii + 1
tCount[ii] = iCount
-- Separate any leading Number from Rest of Address:
sNumber, iNumber, sPre, sRest = string.match(sAddress, "^(%p*(%d+)[^%c%s]*[ %p%d]*)%s+(%W*)(.*)")
if sNumber == nil then
sNumber = ""
end
sNumEnd = string.sub(sNumber, -2) -- move ordinals from Number to Rest of Address
if (sNumEnd == "st") or (sNumEnd == "nd") or (sNumEnd == "rd") or (sNumEnd == "th") then
sRest = sNumber .. " " .. sRest
sNumber = ""
iNumber = 0
end
sNumber = string.gsub(sNumber, "&", "&&") -- ensure ampersand displays OK
if iNumber == nil then
iNumber = 0
sPre, sRest = string.match(sAddress, "^(%W*)(.*)")
end
if iOption == 2 then -- Reverse the order of Address (& Place) parts
tPart = {} -- Table for Parts of Address ( & Place)
tSep = {} -- Table for Separators between Parts
iParts = 0 -- Count of Parts
iSeps = 0 -- Count of Separators
for sPart in string.gmatch(sAddress, "[^,%c]+") do
iParts = iParts + 1
if sPart == nil then sPart = "" end
tPart[iParts] = string.match(sPart, "^%s*(.*)%s*$")
end
for sSep in string.gmatch(sAddress, "[,%c]+") do
iSeps = iSeps + 1
tSep[iSeps] = sSep
end
while iParts - iSeps <= 0 do -- ensure 1 more Parts than Separators
iParts = iParts + 1
tPart[iParts] = ""
end
sRev = tPart[iParts] -- Start with last Part of Address (& Place)
while iSeps > 0 do -- Process Separators and Parts in reverse order
iParts = iParts - 1
sRev = sRev .. tSep[iSeps] .. tPart[iParts]
iSeps = iSeps - 1
end
sRev = string.gsub(sRev, ",", ", ")
-- Reverse sRest for sorting
sRevRest = ""
for sPart in string.gmatch(sRest, "[^,%c]+") do
if sPart == nil then sPart = "" end
sPart = string.match(sPart, "^%s*(.*)%s*$")
sRevRest = sPart .. ", " .. sRevRest
end
end
-- Populate output Tables:
tSortNum[ii] = string.format("%10u", iNumber)
if iOption ~= 2 then
tRest[ii] = ' ' .. sRest -- having removed non-alphabetic prefix for sorting
tNumber[ii] = sNumber
tAddress[ii] = ' ' .. string.gsub(sPre .. sRest, string.char(8), " " .. string.char(133) .. " ")
iLen2 = string.len(tNumber[ii])
if iLen2 > iMax2 then -- Sets maximum address length
iMax2 = iLen2
end
else
tRest[ii] = ' ' .. sRevRest
tAddress[ii] = ' ' .. string.gsub(sRev, string.char(8), " " .. string.char(133) .. " ")
end
iLen = string.len(tAddress[ii])
if iLen > iMax then -- Sets maximum address length
iMax = iLen
end
end
sAddCol = " Address"
if iPlace == 1 then
sAddCol = sAddCol .. " " .. string.char(133) .. " Place"
sSubtitle = sSubtitle .. " (with Place appended)"
end
if iOption == 2 then
sAddCol = sAddCol .. " - Reversed"
sSubtitle = sSubtitle .. " - Reversed"
end
iWid = 4 * iMax -- Sets Address column width
iWid2 = 4 * iMax2 -- Sets Number column width
fhOutputResultSetTitles(sTitle, sTitle, sSubtitle .. " %#c")
fhOutputResultSetColumn('Count', 'integer', tCount, ii, 24, 'align_right')
if iOption ~= 2 then
fhOutputResultSetColumn('No.', 'text', tNumber, ii, iWid2, 'align_right')
end
fhOutputResultSetColumn(sAddCol, 'text', tAddress, ii, iWid, 'align_left')
fhOutputResultSetColumn('', 'text', tRest, ii, 1, 'align_left', iAsort) -- Only for sorting
fhOutputResultSetColumn('', 'text', tSortNum, ii, 1, 'align_right', iNsort) -- Only for sorting
end
Source:Address-Summary-Report3.fh_lua