> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abbyy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sample scripts for creating custom rules

> Sample VBScript, JScript, and C# code for custom FlexiCapture rules: table data checks, value list searches, checkmark groups, and address parsing.

This article provides sample scripts for common custom-rule scenarios in ABBYY FlexiCapture. Where applicable, each example includes both a VBScript and a JScript version.

## Automation rule

This example demonstrates a table data check. The rule checks whether the table data matches the value in the resulting field. The table has columns with the prices and quantities of goods. The rule is written at the level of a section containing the table and the resulting field.

<CodeGroup>
  ```vb VBScript theme={null}
  dim autoRule
  set autoRule = CreateObject( "AutomationRule.CheckDoc" )
  autoRule.CheckResult me.FIELD("cost"), me.FIELD("number"), me.FIELD("Result"), me
  ```

  ```javascript JScript theme={null}
  var autoRule = new ActiveXObject( "AutomationRule.CheckDoc" );
  autoRule.CheckResult( Field("cost"), Field("number"),
      Field("Result"), this );
  ```
</CodeGroup>

### Code of an ActiveX component

The code below is the `CheckDoc` class code from the `AutomationRule` project, used in the scripts above.

```vb theme={null}
Option Explicit

' Checks whether table data matches the result
' column1 - price column
' column2 - quantity column
' resultField - resulting field (<Total> or equivalent)
' docObj - document node being checked
Public Sub CheckResult(ByRef column1 As Object, ByRef column2 As Object, _
ByRef resultField As Object, ByRef docObj As Object)
On Error GoTo err_h
Dim costItems AsObject, numItems AsObject
Dim curCost AsDouble, curNum AsLong, sum AsDouble
Dim result AsDouble
Dim i AsLong
Set costItems = column1.Items
Set numItems = column2.Items
' summing up table data
    sum = 0
For i = 0 To costItems.Count - 1
        curCost = costItems.Item(i).Value
        curNum = numItems.Item(i).Value
        sum = sum + curNum * curCost
Next
   ' comparison accuracy result rounded to the 2nd digit after the decimal point
    result = resultField.Value
If (Round(result, 2) = Round(sum, 2)) Then
        docObj.CheckSucceeded = True
Else
        docObj.CheckSucceeded = False
docObj.ErrorMessage = "Table data does not match the resulting value"
        resultField.Suggest sum
   End If
Exit Sub
err_h:
docObj.ErrorMessage = Err.Description
    docObj.CheckSucceeded = False
End Sub
```

## Search in the variants list

This rule checks whether the field value matches one of the values in a list. If it does not, a rule error flag appears, and the field is given a list of suggested values. Depending on the check result, the field is marked as confidently or not confidently recognized.

<CodeGroup>
  ```vb VBScript theme={null}
  'remember field value
  Dim fieldValue
  fieldValue = me.Field("Field6").Value
  'create list of values for check
  Dim list(5)
  dim i
  for i = 0 to 4
      list(i) = "2" & i
  next
  dim success
  success = false
  'check whether field value matches values in the list
  for i = 0 to 4
  if list(i) = fieldValue Then
          success = true
          exit for
  end if
  next
  'depending on the check result, set a corresponding certainly status for the field
  me.Field("Field6").IsVerified = success
  'fill the list of suggestions for the field a suggestion can be any of the
  'suitable values
  if success = false then
      for i = 0 to 4
  me.Field("Field6").Suggest( list(i) )
      next
  end if
  'place an error flag
  me.CheckSucceeded = success
  ```

  ```javascript JScript theme={null}
  // remember field value
  var fieldValue = Field("Field6").Value;
  // create list of values for check
  var list = new Array(5);
  for( i = 0; i < 5; i++ ) {
      list[i] = "2" + i
  }
  var success = false;
  // check whether field value matches values in the list
  for( i = 0; i < 5; i++ ) {
  if( list[i] == fieldValue ) {
          success = true;
          break;
  }
  }
  // depending on the check result, set a corresponding certainly status for the field
  Field("Field6").IsVerified = success;
  // fill the list of suggestions for the field a suggestion can be any of the
  // suitable values
  if( !success ) {
  for( i = 0; i < 5; i++ ) {
          Field("Field6").Suggest( list[i] );
      }
  }
  // place an error flag
  CheckSucceeded = success;
  ```
</CodeGroup>

## Field match check

This rule checks whether the field has been matched.

<CodeGroup>
  ```vb VBScript theme={null}
  if me.Field("InvoiceNumber").IsMatched then
   me.CheckSucceeded = true
  else
   me.CheckSucceeded = false
   me.ErrorMessage = "Field InvoiceNumber is not matched"
  end if
  ```

  ```javascript JScript theme={null}
  if( Field("InvoiceNumber ").IsMatched ) {
   CheckSucceeded = true;
  } else {
  CheckSucceeded = false;
   ErrorMessage = "Field InvoiceNumber is not matched";
  }
  ```
</CodeGroup>

## Checkmark check

This rule checks whether the checkmark is selected.

<CodeGroup>
  ```vb VBScript theme={null}
  if me.Field("Page status").Value then
      me.CheckSucceeded = true
  else
      me.CheckSucceeded = false
      me.ErrorMessage = "Page status is not checked"
    me.FocusedField = me.Field(Page status)  ""
  end if
  ```

  ```javascript JScript theme={null}
  if( Field("Page status").Value ) {
      CheckSucceeded = true;
  } else {
  CheckSucceeded = false;
      ErrorMessage = "Page status is not checked";
      FocusedField = Field("Page status");
  }
  ```
</CodeGroup>

## Checkmark group check

This rule iterates over all the checkmarks in the group and, if none are selected, selects the first one. The rule is written for the checkmark group level. All the checkmarks in the group have been added to the list of fields included in the rule, and the group itself has been excluded from the list. For the default checkmark (the first one), the ReadOnly flag has been disabled. If there are no checkmarks in the group, a rule error flag is enabled.

This sample iterates over all the fields included in the rule. Since field names are not specified, the code can be used for any checkmark group.

<CodeGroup>
  ```vb VBScript theme={null}
  if me.Fields.Count = 0 then
      me.CheckSucceeded = false
      me.ErrorMessage = "There are no checkmarks in the group"
  else
      dim isChosen, i
      isChosen = false
  for i = 0 to me.Fields.Count - 1
         if me.Fields.Item( i ).Value then
              isChosen = true
              exit for
  end if
  next
  if Not isChosen then
          me.Fields.Item(0).Value = true
      end if
  me.CheckSucceeded = true
  end if
  ```

  ```javascript JScript theme={null}
  if( Fields.Count == 0 ) {
      CheckSucceeded = false;
      ErrorMessage = "There are no checkmarks in the group";
  } else {
      var isChosen = false;
      var i;
  for( i = 0; i < Fields.Count; i++ ) {
          if( Fields.Item( i ).Value ) {
              isChosen = true;
              break;
  }
  }
  if( !isChosen ) {
          Fields.Item(0).Value = true;
      }
  CheckSucceeded = true;
  }
  ```
</CodeGroup>

## Field reliability check

This rule checks the number of uncertain characters in the field and clears the field if that number is three or more. This is an Autocorrection script.

<CodeGroup>
  ```vb VBScript theme={null}
  Dim totQty, suspQty
  Dim i
  totQty = me.Symbols.Count
  suspQty = 0
  for i = 0 to totQty - 1
    if me.Symbols.Item(i).IsSuspicious = true then
      suspQty = suspQty + 1
    end if
  next
  if suspQty >= 3 then
    me.Text = ""
  end if
  ```

  ```javascript JScript theme={null}
  var susp, qty, strpos, i, SC, strposPrev
  strposPrev = 1
  qty = 0
  SC = "1"
  susp = SuspiciousSymbols
  for ( i = 0; i < susp.length; i++) {
      strpos = susp.indexOf (SC,i)
  if ((strpos != strposPrev) && (strpos != -1)) {
        qty = qty + 1
        strposPrev = strpos
      }
  }
  if (qty >= 3) {
    text = ""
  }
  ```
</CodeGroup>

## Character replacement without losing regions and verification flags

The script replaces `+` with `&` without losing information about regions and verification flags. This is an Autocorrection script.

```vb theme={null}
Dim totQty
Dim i
totQty = me.Symbols.Count
for i = 0 to totQty - 1
if me.Symbols(i).Symbol = "+" then
    me.Symbols(i).Symbol = "&"
end if
next
```

## Batch integrity check

Checks whether the number of documents specified on the control page matches the batch inventory and the number of documents actually processed. If the numbers do not match, an error is returned.

<CodeGroup>
  ```vb VBScript theme={null}
  dim DQty
  dim i
  for i = 0 to me.Batch.Documents.Count - 1
    if me.Batch.Documents.Item(i).DefinitionName = "Inv" then
      DQty = me.Batch.Documents.Item(i).IndexedItemValue("DocQty")
      exit for
  end if
  next
  dim AcQty
  AcQty = me.Batch.Documents.Count
  if acqty <> DQty then
    me.CheckSucceeded = false
    me.ErrorMessage = "Incorrect number of documents in the batch:" & " " & AcQty& ". " & "Expected number:" & " " & DQty & "!"
  end if
  ```

  ```javascript JScript theme={null}
  for ( i = 0; i < [Batch.Documents.Count - 1]; i++ ) {
  var TemplName = Batch.Documents.Item(0).DefinitionName;
    if (TemplName = "Inv") {
      var DQty = Batch.Documents.Item(i).IndexedItemValue("DocQty");
      break ;
  }
  }
  var AcQty = Batch.Documents.Count -1
  if (AcQty != DQty) {
      CheckSucceeded = false;
      ErrorMessage = "Incorrect number of documents in the batch:" + " " + AcQty + "." + "Expected number:" + " " + DQty +"!" ;
  }
  ```
</CodeGroup>

## Counting the number of documents and pages in a document set

This script counts the number of documents and pages in a document set and throws an error if the set contains an element of an unknown type.

```csharp theme={null}
int subDocumentsCount = 0;
int pagesCount = 0;
IBatchItem asBatchItem = Context.Document.AsBatchItem;
IBatchItems items = asBatchItem.ChildItems;
foreach (IBatchItem item in items)
{
if ( item.Type == TBatchItemType.BIT_Page )
{   pagesCount ++;  }
else if( item.Type == TBatchItemType.BIT_Document )
{   subDocumentsCount ++; }
else
{
Context.CheckSucceeded = false;
Context.ErrorMessage = "Unknown type of element in set";
}
}
Context.Field("Field").Text = subDocumentsCount.ToString() + " " + pagesCount.ToString();
```

## Address parsing

The script parses the address into the following components: ZIP Code, Country, City, and Street. It is called on a portion of the source field.

```csharp theme={null}
//-----------------------------------------
var collectionName = "";
IFieldExtractor extractor = Context.GetFieldExtractor();
extractor.ParseAddress();
var city = extractor.ExtractedObjects( collectionName, "NerCity" );
var country = extractor.ExtractedObjects( collectionName, "NerCountry" );
var zip = extractor.ExtractedObjects( collectionName, "NerZipCode" );
var street = extractor.ExtractedObjects( collectionName, "NerStreet" );
for( var i = 0; i < city.Count; i++ ) {
extractor.PutSpanToField( city.Item(i).Span, Context.Field("City") );
}
for( var i = 0; i < country.Count; i++ ) {
extractor.PutSpanToField( country.Item(i).Span, Context.Field("Country") );
}
for( var i = 0; i < zip.Count; i++ ) {
extractor.PutSpanToField( zip.Item(i).Span, Context.Field("ZIP") );
}
for( var i = 0; i < street.Count; i++ ) {
extractor.PutSpanToField( street.Item(i).Span, Context.Field("Street") );
}
//-------------------------------------
```
