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 FunctionSempre 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