| N. | Codice | Descrizione |
| 1. | xxx-xxx-xxx-xxx-00100 | Rif: yyy-yyy-yyy-yyy-01234 Descrizione... |
| 2. | xxx-xxx-xxx-xxx-00110 | Rif: yyy-yyy-yyy-yyy-01234 Descrizione... |
| 3. | xxx-xxx-xxx-xxx-00120 | Rif: yyy-yyy-yyy-yyy-01235 Descrizione... |
| ... | ||
L'ultima tabella rappresentava invece i requisiti utente originari da cui i requisiti software di dettaglio erano stati estrapolati:
| Codice | Descrizione | Dettaglio |
| yyy-yyy-yyy-yyy-01234 | blah blah blah | |
| yyy-yyy-yyy-yyy-01235 | bluh bluh bluh |
In pratica manualmente avrei dovuto cercare tutti i riferimenti e riportare nella colonna "Dettaglio" l'elenco dei requisiti con quel riferimento:
| Codice | Descrizione | Dettaglio |
| yyy-yyy-yyy-yyy-01234 | blah blah blah |
xxx-xxx-xxx-xxx-00100 xxx-xxx-xxx-xxx-00110 |
| yyy-yyy-yyy-yyy-01235 | bluh bluh bluh | xxx-xxx-xxx-xxx-00120 |
Seguendo la regola automatizzare a tutti i costi mi sono rivolto a una macro in VBA non semplice, sicuramente da ottimizzare, ma che ha raggiunto lo scopo:
Option Explicit
Const rifTag = "Rif: " ' Tag che identifica il requisito di riferimento
Const firstTable As Integer = 18 ' Indice della prima tabella da esaminare
Const reqDettLength = 21 ' Lunghezza del codice del requisito di dettaglio
' Compila la tabella con la mappa dei requisiti
Sub requirementsMap()
Dim element As String ' Elemento estratto dalla tabella
Dim lastTable As Integer ' Ultima tabella da esaminare
lastTable = ActiveDocument.Tables.Count - 1
Const firstRowIndex As Integer = 1 ' Prima riga da esaminare
Dim lastRowIndex As Integer ' Ultima riga da esaminare
Dim reqId As Integer ' Contatore dei requisiti
reqId = 1
Dim tableIndex As Integer ' Cursore delle tabelle
Dim currentTable
' Scorre le tabelle
For tableIndex = firstTable To lastTable
currentTable = ActiveDocument.Tables(tableIndex)
lastRowIndex = currentTable.Rows.Count
Dim currentRowIndex As Integer ' Cursore delle righe
Dim currentRow
' Scorre le righe della tabella corrente
For currentRowIndex = firstRowIndex To lastRowIndex
currentRow = currentTable.Rows(currentRowIndex)
Dim reqDett As String ' Requisito di dettaglio (prima colonna della tabella in esame)
reqDett = extractReqDett(currentRow)
Dim reqGen As String ' Requisito generale (indicato dalla parola "Rif. ")
reqGen = extractReqGen(currentRow)
Dim reqIndex ' Indice del requisito generale
Dim reqMap ' Tabella contenente la mappa dei requisiti
Dim foundRow ' Riga del requisito generale (-1 se non trovato)
Dim cellContent ' Contenuto della cella DETTAGLIO
If (Len(reqDett) = reqDettLength) Then
reqIndex = findInTable(reqGen)
' Se il requisito generale è stato trovato
If (reqIndex > -1) Then
reqMap = ActiveDocument.Tables(ActiveDocument.Tables.Count)
foundRow = reqMap.Rows(reqIndex)
cellContent = foundRow.Cells(3)
foundRow.Cells(3) = cellContent + reqDett
End If
reqId = reqId + 1
End If
Next
Next
End Sub
' Prendo solo il codice di 21 caratteri del
' requisito di dettaglio escludendo la descrizione
Function extractReqDett(currentRow)
Dim element As String
element = extractCell(currentRow, 2)
If Len(element) > 21 Then
extractReqDett = Left(element, 21)
Else
extractReqDett = element
End If
End Function
' Prendo solo il codice del requisito
' generale tagliando via "Rif. "
Function extractReqGen(currentRow)
Dim reqGen As String
reqGen = extractCell(currentRow, 3)
If (Len(reqGen) > Len(rifTag)) Then
Dim beginsWith As String
beginsWith = Left(reqGen, Len(rifTag))
If (beginsWith = rifTag) Then
extractReqGen = Right(reqGen, Len(reqGen) - Len(rifTag)) ' Prendo solo il codice escludendo "Rif. "
Else
extractReqGen = "???"
End If
Else
extractReqGen = "???"
End If
End Function
' Estrae una cella di una tabella tagliando al primo
' ritorno a capo ed eliminando gli spazi a contorno
Function extractCell(row, cellIndex) As String
extractCell = Trim(truncateAtCRLF(row.Cells(cellIndex)))
End Function
' Tronca una stringa al primo CR/LF
Function truncateAtCRLF(text As String) As String
truncateAtCRLF = truncate(text, Chr(13))
End Function
' Tronca una stringa alla prima occorrenza del delimitatore
Function truncate(text As String, delimiter As String) As String
Dim delimiterIndex
delimiterIndex = InStr(1, text, delimiter, vbTextCompare)
Dim temp As String
If (delimiterIndex > 1) Then
temp = Left(text, delimiterIndex - 1)
Else
temp = text
End If
truncate = temp
End Function
' Ritorna l'indice della riga della tabella in cui si trova S
Function findInTable(S As String) As Integer
Dim reqMap
reqMap = ActiveDocument.Tables(ActiveDocument.Tables.Count)
Dim j As Integer
j = 2 ' Skip riga d'intestazione
Dim rowFound As Integer
rowFound = -1
Dim currentRow
Dim reqId
While (j <= reqMap.Rows.Count And rowFound = -1)
currentRow = reqMap.Rows(j)
reqId = truncate(currentRow.Cells(1), " ")
If (reqId = S) Then rowFound = j
j = j + 1
Wend
findInTable = rowFound
End Function
Sempre bene accette le idee per migliorare il codice, ovviamente (per esempio: la ricerca lineare sulla tabella di destinazione non mi piace molto, in Java avrei usato una HashTable per indicizzare i contenuti).
Nessun commento:
Posta un commento