> ## 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.

# 補助要素とヌル仮説を使用して FlexiLayout を簡素化する

> 複数の要素に共通する検索制約が満たされたことを、ヌル仮説で示す補助ダミー要素を使用して、複雑な FlexiLayout コードを簡素化します。

このメソッドは、複数の要素に対して同じ複雑な検索制約を確認する必要がある場合に使用します。基本的な考え方は、制約の確認と計算を補助要素内で一度だけ実行することです。

制約の確認結果に応じて、対象の要素を検索するかどうかが決まり、見つかった仮説または見つからなかった仮説が、制約が満たされているかどうかを示すマーカーになります。

<div id="how-the-dummy-element-signals-that-the-constraints-are-met">
  ## ダミー要素が制約条件を満たしていることを示すしくみ
</div>

この補助要素は、`DontFind()` 関数 (つまり「検索を停止する」) がアクティブ化されていない限り、画像上で常に何らかのものを検出できるように作成されます。仮説の数は多くなりすぎないようにする必要があります。多すぎると、仮説ツリーが過度に拡張され、FlexiLayout のマッチング時間が長くなるためです。

これを実現するには、たとえば **Object Collection** 型または **Paragraph** 型の要素を使用できます。これらの要素は常に 1 つの仮説を生成し、その仮説には検索領域内にある指定型のすべてのオブジェクトが含まれます。

ダミー要素の **Advanced pre-search relations** セクションには、プロジェクトツリー内でダミー要素より下にある一部の要素について確認するための条件セットが含まれています。すべての条件が満たされると、ダミー要素に対して `DontFind()` 関数が呼び出されます。

この場合、ダミー要素に対してヌル仮説が生成され、FlexiLayout Studio が他の要素の検索を開始する際に、すべての条件が満たされたことを示すマーカーとして機能します。これにより、複数の要素に対して同じ複雑な制約条件をチェックする代わりに、ダミー要素の `IsNull` チェックだけを実行するようになります。

<Note>
  このメソッドを使うと、コードの記述がよりわかりやすくなります。さらに、制約条件を編集する必要がある場合も、ダミー要素の説明だけを修正すれば済みます。コードを複製する際に、論理エラーや構文エラーが発生する可能性を低減できます。
</Note>

<Note>
  将来の製品バージョンでは、グループのサブ要素領域で変数を作成できるようになる予定です。そうなれば、制約条件の確認結果は異なる変数の値に保存されるようになります。

  現在のメソッドは一時的な解決策 (workaround) であり、現行バージョンの FlexiLayout Studio で Advanced セクションのコードを簡潔にするのに役立ちます。
</Note>

<div id="the-two-invoice-layouts-in-the-sample-project">
  ## sample プロジェクト内の2種類の請求書レイアウト
</div>

プロジェクト `1.fsp` (フォルダー `%public%\ABBYY\FlexiCapture\12.0\Samples\FLS\Tips and Tricks\Auxiliary element`) では、このメソッドがどのように機能するかを示しています。

これらの画像では、次のfieldを見つけることが目的です: 「請求書番号」、「請求日」、「会社名」、「会社住所」。

2種類の異なる請求書を処理する必要があるとします:

* 「会社名」と「会社住所」のfieldは、「請求書番号」のfieldより上にあります。
* 「会社名」と「会社住所」のfieldは、「請求書番号」のfieldより下にあります。

画像を見るとわかるように、「会社名」と「会社住所」のfieldには名前が付いていないため、名前を手がかりにデータfieldを探す標準的な手順は使えません。

ただし、ここには一定のパターンがあります。日付フィールドが請求書番号の右側にある場合、会社名と住所は「請求書番号」のfieldの下にあります (1ページ目と3ページ目) 。日付フィールドが請求書番号 field の下にある場合、会社情報は「請求書番号」のfieldの上にあります (2ページ目と4ページ目) 。

このパターンを踏まえると、まず「請求書番号」と「請求日」のfieldの位置を特定し、その後、この2つを基準に相互の位置関係を指定して他のfieldを検出するのが最適です。

<div id="search-for-the-date-field-with-two-sets-of-constraints">
  ## 2組の制約条件を使用して日付フィールドを検索する
</div>

このプロジェクトには、要素 **InvoiceHeader**、**InvoiceNum**、**DateHeader** を含む グループ要素 **InvoiceGroup** と、グループ要素 **DateGroup** があります。これらのサブ要素は、field名、および field "請求書番号" と "請求日" を検出するために必要です。

<Note>
  日付検索の方法について詳しくは、[高品質または低品質の認識後の日付検索](/ja/flexi-capture/fls/tips-tricks/date2)を参照してください。このセクションでは、現在のプロジェクトにおける日付検索の制約条件のみを説明します。
</Note>

ご覧のとおり、画像内の日付フィールドには名前が付いていないことがあります。

そのため、日付フィールドを検索する際には、名前が検出された場合と、名前が検出されなかった場合の2組の制約条件を指定する必要があります (特別なケースとして、名前がページ上に存在していても、たとえばノイズが原因で検出されないことがあります) 。

```text theme={null}
if not DateHeader.IsNull then
{ RightOf: DateHeader.Rect.Right;
Below: DateHeader.Rect.Top - 30dt;
Above: DateHeader.Rect.Bottom + 30dt;
}
else
{ RectArray ar;
Let ar1 = Rect (InvoiceNum.Rect.Right, InvoiceNum.Rect.Top-30dt, PageRect.Right, InvoiceNum.Rect.Bottom + 30dt);
Let ar2 = Rect (InvoiceHeader.Rect.Left, InvoiceHeader.Rect.Bottom, InvoiceHeader.Rect.Right + 300dt, InvoiceHeader.Rect.Bottom + 150dt);
ar = RectArray (ar1);
ar.Add (ar2);
RestrictSearchArea (ar);
}
```

日付フィールド名が検出された場合 (制約 `if not DateHeader.IsNull` がチェックされる場合) 、検索は日付フィールド名を基準に実行されます。つまり、名前の右側で、同じ水準上にあり、縦方向のずれにはある程度の許容範囲を設けて検索します。

```text theme={null}
{ RightOf: DateHeader.Rect.Right;
Below: DateHeader.Rect.Top - 30dt;
Above: DateHeader.Rect.Bottom + 30dt;
}
```

そうでない場合、検索領域は 2 つの矩形に分割されます。1 つは請求書番号の右側で、請求書番号と同じ高さにあり、もう 1 つは請求書 field の下にあります。

<Note>
  簡単のため、画像は高品質で、field "請求書番号" とその名前は常に検出されるものとします。

  実際には、これらの要素のプロパティを呼び出す前に、`IsNull` チェックを実行する必要があります。要素が検出されない場合、その後の検索は対応する要素の検索領域を基準に実行されるためです。
</Note>

<Frame>
  <img src="https://mintcdn.com/abbyy/lqYknuOmCa79141v/images/flexi-capture/fls/auxillary_element.png?fit=max&auto=format&n=lqYknuOmCa79141v&q=85&s=f9a44ef58fb998dfe5322e344ae33470" alt="日付フィールド名が検出されない場合に、ABBYY FlexiLayout Studio で、日付フィールドの検索領域が請求書番号 field の右側および下側にある矩形の array として定義されていることを示すスクリーンショット。" width="716" height="406" data-path="images/flexi-capture/fls/auxillary_element.png" />
</Frame>

<div id="penalize-date-hypotheses-far-from-the-invoice-fields">
  ### 請求書のfieldから離れた日付の仮説にペナルティを適用する
</div>

**Date** 要素の**Advanced post-search relations** sectionには、次のコードがあります。

```text theme={null}
if (DateHeader.IsNull) and (not IsNull) then
{if (not InvoiceHeader.IsNull) then
{ FuzzyQuality: Rect.Left - InvoiceHeader.Rect.Right, {0, 0, 0, 50000}*dt;
FuzzyQuality: Rect.Top - InvoiceHeader.Rect.Bottom, {-50000, 0, 0, 50000}*dt;
}
if (not InvoiceNum.IsNull) then
{ FuzzyQuality: Rect.Left - InvoiceNum.Rect.Right, {0, 0, 0, 50000}*dt;
FuzzyQuality: Rect.Top - InvoiceNum.Rect.Bottom, {-50000, 0, 0, 50000}*dt;
}
}
```

このコードは、日付フィールド名が検出されない場合、請求書fieldの名前および field "請求書番号" 自体からの距離に応じて、日付仮説の品質に影響します。

指定した各fieldまでの距離が長いほど、対応する仮説へのペナルティは大きくなります。つまり、field "請求書番号" に最も近い日付フィールドが検索されます。

<Note>
  これらの関数の使用方法について詳しくは、[Nearest と FuzzyQuality を使用した要素の検索](/ja/flexi-capture/fls/tips-tricks/date9)を参照してください。
</Note>

<div id="search-constraints-for-the-dateasstring-element">
  ### DateAsString 要素の検索制約
</div>

**DateAsString** 要素にも同じ検索制約が指定されていますが、その **Advanced post-search relations** セクションでは、先ほど示したコードにさらに 1 行追加されています。

```text theme={null}
FuzzyQuality: 600dt - Width, {0, 0, 0, 50000}*dt;
```

この行は日付の検索時に必要で、より短い文字列よりも、アルファベット文字が長く連続する仮説を優先するためのものです。

さらに、**DateAsString** 要素の **Search Constraints** タブでは、日付を文字列として検索する際に、**InvoiceNum** 要素の Region を除外するよう指定されています。

これは、簡略化のため、要素 **Date** の **Advanced pre-search relations** セクションで指定したものと同じ検索制約を、要素 **DateAsString** に重ねて設定しないことにしたためです。検索領域には `RestrictSearchArea (Date.Rect);` を指定しています。つまり、要素 **DateAsString** の object を、要素 **Date** の Fuzzy Rectangle の領域内で検索するよう FlexiLayout Studio に指示することになります。要素 **Date** の検索領域は、矩形の array として表すことができます。

要素 **Date** に対してヌル仮説が生成されると、検索領域を囲む矩形が現在の要素の矩形 (`Rect`) として扱われます。下の画像からわかるように、この矩形には要素 **InvoiceNum** で表される field "請求書番号" も含まれます。

条件によっては (たとえば日付フィールドのノイズが非常に多い場合) 、日付 field ではなく、要素 **DateAsString** が請求書番号の field を検出してしまうことがあります。これは、この要素に指定された文字 (数字を含む) には書式上の制約がないためです。

<Frame>
  <img src="https://mintcdn.com/abbyy/lqYknuOmCa79141v/images/flexi-capture/fls/auxillary_element2.png?fit=max&auto=format&n=lqYknuOmCa79141v&q=85&s=a1caa464b42e23727332aadb1c046913" alt="ABBYY FlexiLayout Studio のスクリーンショット。未検出の Date 要素に対する RestrictSearchArea で定義された DateAsString 要素の検索領域が示されており、InvoiceNum 要素で表される請求書番号 field も含まれています。" width="684" height="467" data-path="images/flexi-capture/fls/auxillary_element2.png" />
</Frame>

<div id="check-the-field-arrangement-with-the-shamelement-auxiliary-element">
  ## ShamElement 補助要素で field の配置を確認する
</div>

field "請求書番号" と "請求日" を検索するために必要な要素を記述したら、次は field "会社名" と "会社住所" を検索します。

このプロジェクトでは、**ShamElement** という名前の **Paragraph** 要素を使用します。この要素は補助要素として機能し、field "請求書番号" と "請求日" の相対的な位置関係を確認するためだけに使用されます。

補助要素の **Advanced pre-search relations** セクションには、次のコードが含まれています。

```text theme={null}
Let Date1 = InvoiceGroup.DateGroup.Date;
Let Date2 = InvoiceGroup.DateGroup.DateAsString;
Let DateGroup = InvoiceGroup.DateGroup;
Let InvoiceHeader = InvoiceGroup.InvoiceHeader;
Let InvoiceNumber = InvoiceGroup.InvoiceNum;

if ((not InvoiceHeader.IsNull) or (not InvoiceNumber.IsNull)) and
(
((Date1.IsNull == FALSE) and ((max (InvoiceHeader.Rect.YCenter - Date1.Rect.YCenter, Date1.Rect.YCenter - InvoiceHeader.Rect.YCenter ) < 30dt) or (max (InvoiceNumber.Rect.YCenter - Date1.Rect.YCenter, Date1.Rect.YCenter - InvoiceNumber.Rect.YCenter ) < 30dt)) and ((Date1.Rect.Left - InvoiceHeader.Rect.Right > 100dt) or (Date1.Rect.Left - InvoiceNumber.Rect.Right > 50dt)))
or
((Date2.IsNull == FALSE) and ((max (InvoiceHeader.Rect.YCenter - Date2.Rect.YCenter, Date2.Rect.YCenter - InvoiceHeader.Rect.YCenter ) < 30dt) or (max (InvoiceNumber.Rect.YCenter - Date2.Rect.YCenter, Date2.Rect.YCenter - InvoiceNumber.Rect.YCenter ) < 30dt)) and ((Date2.Rect.Left - InvoiceHeader.Rect.Right > 100dt) or (Date2.Rect.Left - InvoiceNumber.Rect.Right > 50dt)))
)
then
{ Dontfind(); }
else
{ Below: PageRect.Top; }
```

このコードでチェックされる制約自体は単純ですが、コードそのものはかなり大がかりです。

つまり、**Date** または **DateAsString** 要素のいずれかで検出された日付フィールドが、請求書番号 field の右側にあり、かつ同じ高さにある場合 (垂直方向の許容差は 30 dt) 、補助要素に対してヌル仮説を生成するよう FlexiLayout Studio に指示します。

それ以外の場合は、**ShamElement** 要素がページ上端より下方で検索されます。補助要素は追加の検索条件を持たない **Paragraph** 要素であるため、ページ上のすべての text objects を囲み、1 つの仮説が生成されます。

チェックすべき制約のほとんどは直感的に理解できるため、ここではその中でも最も複雑なものだけを説明します。

```text theme={null}
max (InvoiceHeader.Rect.YCenter - Date1.Rect.YCenter, Date1.Rect.YCenter - InvoiceHeader.Rect.YCenter ) < 30dt
```

コードのこの部分では、日付フィールド (この場合は **Date** 要素によって検出された場合) が、field 名 "請求書番号" の要素と同じ水平位置にあることを確認します。日付は、名前よりわずかに上または下にある場合があります (スキャン時や文書記入時に生じる可能性のある誤差のためです) 。

最大差は 30 dt に指定されています。field "請求日" と "請求書番号" の相対的な縦位置関係も、同じメソッドで確認されます。

```text theme={null}
Date1.Rect.Left - InvoiceHeader.Rect.Right > 100dt
```

この行では、日付フィールドが field "請求書番号" の名前の右側にあることを確認します (つまり、日付の左境界の座標が、名前の右境界の座標より大きいことを意味します) 。

許容値として 100dt を指定しているのは、請求書番号そのものが名前と日付の間に入る必要があるためです。日付フィールドは field "請求書番号" の右側にあります。

次に、このチェックのすべての条件を **DateAsString** 要素にも複製します。

コードが正しいことを確認するには、すべてのページで FlexiLayout マッチング手順を実行します。日付フィールドが請求書番号の右側にある 1 ページ目と 3 ページ目では、**ShamElement** 要素に対してヌル仮説が生成されました。一方、残りの 2 ページではテキストフラグメントが検出されました。

<Frame>
  <img src="https://mintcdn.com/abbyy/lqYknuOmCa79141v/images/flexi-capture/fls/auxillary_element3.png?fit=max&auto=format&n=lqYknuOmCa79141v&q=85&s=c52bdce87a889d29654e1a4cc998ca34" alt="ABBYY FlexiLayout Studio の FlexiLayout マッチング結果のスクリーンショット。日付フィールドが請求書番号の右側にある 1 ページ目と 3 ページ目で、ShamElement 補助要素に対してヌル仮説が生成されている様子を示しています。" width="611" height="474" data-path="images/flexi-capture/fls/auxillary_element3.png" />
</Frame>

<div id="search-for-the-company-name-relative-to-the-invoice-fields">
  ## invoice fieldsを基準に会社名を検索する
</div>

会社の詳細を検出するため、このProjectではグループ要素 **CompanyGroup** を使用します。これは、**Character String** 型の要素 **CompanyName** (テスト画像では会社名は1行で記載されています) と、**Paragraph** 型の要素 **住所** をグループ化したものです。後者の要素は、会社住所を含むブロックを検索するために使用されます。

この補助要素を使用することで、Advanced pre-search relations セクションで要素の検索制約を記述するコードを簡潔にできます。

補助要素が検出されない場合 (つまり、その要素に対してヌル仮説が生成される場合) 、日付フィールドはinvoice fieldの右側にあることを意味します。この場合、field "会社名" は field "請求書番号" の下で検索されます。

補助要素が検出された場合、field "会社名" は field "請求書番号" の上で検索されます。

```text theme={null}
if ShamElement.IsNull then
{ Below: InvoiceGroup.InvoiceHeader;
Below: InvoiceGroup.InvoiceNum;
NearestY: PageRect.Top;
}
else
{ Above: InvoiceGroup.InvoiceHeader;
Above: InvoiceGroup.InvoiceNum;
}
```

<Note>
  この場合は `Nearest` function を使用できます。これにより、会社名を含む field を明確かつ正確に特定できます (同じ検索制約に一致するオブジェクトはありません) 。
</Note>

**CompanyName** element の **Advanced post-search relations** section には、次のコードが含まれています。

```text theme={null}
if not IsNull then
{ FuzzyQuality: Rect.Left - PageRect.Left, {0, 0, 0, 50000}*dt;
FuzzyQuality: Rect.Top - PageRect.Top, {0, 0, 0, 50000}*dt;
FuzzyQuality: 100dt - Height, {0, 0, 0, 10000}*dt;
}
```

このコードは、単一行のfield「会社名」を請求書番号のfieldより上で検索する場合に機能します。検索対象のfieldsには名前がありません。同時に、「会社名」と「会社住所」のfieldsの相対的な位置関係は、2ページ目と4ページ目で異なります。

制約 `Above: InvoiceGroup.InvoiceHeader;` および `Above: InvoiceGroup.InvoiceNum;` は、会社名の文字列だけでなく、住所field内の各文字列によっても満たされます。

<Frame>
  <img src="https://mintcdn.com/abbyy/lqYknuOmCa79141v/images/flexi-capture/fls/auxillary_element4.png?fit=max&auto=format&n=lqYknuOmCa79141v&q=85&s=661fd13f411e171cfa77ad25abf2c445" alt="ABBYY FlexiLayout Studio のスクリーンショット。InvoiceHeader 要素および InvoiceNum 要素に対する Above 制約が、会社名の文字列と住所fieldの各行の両方によって満たされていることを示しています。" width="611" height="474" data-path="images/flexi-capture/fls/auxillary_element4.png" />
</Frame>

生成されたすべての仮説の中から唯一正しい仮説を選択するために、**Advanced post-search relations** セクションで次のコードを使用します。

次の行

```text theme={null}
FuzzyQuality: Rect.Left - PageRect.Left, {0, 0, 0, 50000}*dt;
```

および

```text theme={null}
FuzzyQuality: Rect.Top -PageRect.Top, {0, 0, 0, 50000}*dt;
```

プログラムに対し、画像の下端および右端の境界に近いオブジェクトを持つ仮説に、より強いペナルティを適用するよう指示します。

ただし、2ページ目では、field「会社名」は住所 field の左側にありますが、その上端の行より下に位置しています。したがって、前述の制約だけでは目的の field「会社名」を検出するには不十分であり、もう1つ制約が必要です。

```text theme={null}
FuzzyQuality: 100dt - Height, {0, 0, 0, 10000}*dt;
```

この行では、生成された仮説ごとに、FlexiLayout Studio にすべての行の高さをチェックするよう指示します。行内の文字の背が高いほど、対応する仮説の品質も高くなります。

FlexiLayout のマッチング後、すべてのページで field "会社名" が正常に検出されたことを確認できます。

<div id="search-for-the-address-field-with-the-auxiliary-element">
  ## 補助要素を使用して住所 field を検索する
</div>

住所 field を検出するには、**住所** 要素の **Advanced pre-search relations** セクションに次のコードを記述します。

```text theme={null}
if ShamElement.IsNull then
{ Below: CompanyName;
Above: TotalSumHeader.Rect.Top;
}
else
{
Above: InvoiceGroup.InvoiceHeader;
Above: InvoiceGroup.InvoiceNum;
RightOf: CompanyName.Rect.Left;
Exclude: CompanyName;
}
```

ここでも補助要素 **ShamElement** を使用することで、コードを簡潔にできます。

これで FlexiLayout の作成は完了です。FlexiLayout のマッチング手順を実行すると、すべての field が正常に検出されていることを確認できます。
