# Term's Format

A **Term** is the core data type in RegexSolver. It represents a **regular language** (a set of strings), and can be expressed in two interchangeable forms:

* **Regex**: a regular expression pattern
* **FAIR**: a stable binary encoding of an automaton

Both forms describe the same language and can be used everywhere in the API.

## The life of a Term

A Term passes through four stages:

1. **You create one**, usually with `Term.regex(...)`, holding a pattern.
2. **You send it** to an operation, alone or alongside others.
3. **You get one back**, often in FAIR rather than regex form, because that is what the operation produced. It is a normal Term and goes straight into the next call.
4. **You reuse it.** Answers about a single Term (cardinality, length, pattern) are stored on it. Asking again on the same object skips the API, so keep the Term rather than rebuilding it.

What a returned Term does **not** carry is a readable pattern. That is a separate step, covered in [Getting the regex pattern](#getting-the-regex-pattern) below.

## Formats

### Regex (Regular Expression)

RegexSolver supports **pure regular expressions** (regular language only), with the following rules:

1. **Implicit Anchoring**
   Patterns always match the full string. `abc` matches `"abc"`, but not `"xabc"` or `"abcx"`.

2. **No Lookaround**
   Constructs like `(?=...)` and `(?<=...)` are not supported.

3. **Greedy Quantifiers Only**
   Ungreedy forms (`*?`, `+?`, `??`) are parsed but treated as greedy.

4. **Dot Matches Everything**
   `.` matches any unicode character, including `\n`.

5. **No Features Outside Regular Languages**
   Backreferences like `\1` are not supported and will return an error.

Regex parsing is powered by Rust's [`regex-syntax`](https://docs.rs/regex-syntax/latest/regex_syntax/) parser. Some unsupported syntax may parse, but will not influence matching semantics.

### FAIR (Fast Internal Automaton Representation)

FAIR is a portable encoding of an automaton:

* Encoded using [**Z85**](https://rfc.zeromq.org/spec/32/) (ASCII-safe, compact, padded)
* Length varies with automaton complexity
* Opaque and **not editable**, but fully reusable
* Skips regex parsing and compilation when used, improving performance

Use FAIR to **cache**, **store**, or **chain** results without reprocessing.

## Choosing the response format

By default the engine converts nothing: you get back whatever form the operation naturally produced. Which form that is depends on the operation:

| Operation | Default result |
| :--- | :--- |
| `union`, `concat`, `repeat` | **Regex**, when every input Term was a regex. FAIR as soon as one input was FAIR. |
| `intersection`, `difference`, `complement` | **FAIR**, always. These are computed on automata. |

Leaving the default alone is the right choice while you are chaining operations, because it never spends time on a conversion you did not ask for.

Set `responseFormat` when you want to override that. The examples throughout these docs force `regex` so their output is printable, which is convenient for learning and worth being deliberate about in real code: on a heavy operation, forcing `regex` makes the conversion draw on the same time budget as the operation itself. See [Heavy Operations](/advance-usage/heavy-operations).

<CodeTabs defaultValue="java">
<CodeTabs.Tab value="java" label="Java">
Force `regex` output:
```java
RegexSolverClient client = RegexSolverClient.builder()
    .apiToken(System.getenv("REGEXSOLVER_API_TOKEN"))
    .build();
Term term = Term.regex("abcde");

OperationOptions operationOptions = OperationOptions.builder()
        .responseFormat(ResponseFormat.REGEX);
Term result = client.union(List.of(term, Term.regex("de")), operationOptions);

System.out.println(result); // regex=(abc)?de
```

Force `fair` output:
```java
RegexSolverClient client = RegexSolverClient.builder()
    .apiToken(System.getenv("REGEXSOLVER_API_TOKEN"))
    .build();
Term term = Term.regex("abcde");

OperationOptions operationOptions = OperationOptions.builder()
        .responseFormat(ResponseFormat.FAIR);
Term result = client.union(List.of(term, Term.regex("de")), operationOptions);

System.out.println(result); // fair=...
```
</CodeTabs.Tab>

<CodeTabs.Tab value="javascript" label="JavaScript">
Force `regex` output:
```javascript
const client = new RegexSolverClient({ apiToken: process.env.REGEXSOLVER_API_TOKEN });
const term = Term.regex('abcde');

const result = await client.union(term, Term.regex('de'), { responseFormat: ResponseFormat.REGEX });
console.log(result); // regex=(abc)?de
```

Force `fair` output:
```javascript
const client = new RegexSolverClient({ apiToken: process.env.REGEXSOLVER_API_TOKEN });
const term = Term.regex('abcde');

const result = await client.union(term, Term.regex('de'), { responseFormat: ResponseFormat.FAIR });
console.log(result); // fair=...;
```
</CodeTabs.Tab>

<CodeTabs.Tab value="python" label="Python">
Force `regex` output:
```python
client = RegexSolverClient(api_token=os.getenv("REGEXSOLVER_API_TOKEN"))
term = Term.regex(r"abcde")

result = client.union(term, Term.regex(r"de"), response_format=ResponseFormat.REGEX)
print(result) # regex=(abc)?de
```

Force `fair` output:
```python
client = RegexSolverClient(api_token=os.getenv("REGEXSOLVER_API_TOKEN"))
term = Term.regex(r"abcde")

result = client.union(term, Term.regex(r"de"), response_format=ResponseFormat.FAIR)
print(result) # fair=...
```
</CodeTabs.Tab>

</CodeTabs>

## Getting the regex pattern

Regardless of the format of a Term it is possible to get the associated regex pattern:

<CodeTabs defaultValue="java">
<CodeTabs.Tab value="java" label="Java">
```java
RegexSolverClient client = RegexSolverClient.builder()
    .apiToken(System.getenv("REGEXSOLVER_API_TOKEN"))
    .build();
Term a = Term.fair("<uw$8AJYkaU].HFn1kT[tx*-VAZ8usSKXcEKZ[wx:F8vYuR-b?tFFk1eM2RXs9yuu5dakz7r/{!AW9/(hK0]knHS&Q]!@K=ahmGr1Dbjb5(XE1UT%Ab@8rXvYop}$");
Term b = Term.regex("[a-z]+");

String r1 = client.getPattern(a);
System.out.println(r1); // deabc

String r2 = client.getPattern(b);
System.out.println(r2); // [a-z]+
```
</CodeTabs.Tab>

<CodeTabs.Tab value="javascript" label="JavaScript">
```javascript
const client = new RegexSolverClient({ apiToken: process.env.REGEXSOLVER_API_TOKEN });
const a = Term.fair("<uw$8AJYkaU].HFn1kT[tx*-VAZ8usSKXcEKZ[wx:F8vYuR-b?tFFk1eM2RXs9yuu5dakz7r/{!AW9/(hK0]knHS&Q]!@K=ahmGr1Dbjb5(XE1UT%Ab@8rXvYop}$");
const b = Term.regex("[a-z]+");

const r1 = await client.getPattern(a);
console.log(r1); // deabc

const r2 = await client.getPattern(b);
console.log(r2); // [a-z]+
```
</CodeTabs.Tab>

<CodeTabs.Tab value="python" label="Python">
```python
client = RegexSolverClient(api_token=os.getenv("REGEXSOLVER_API_TOKEN"))
a = Term.fair("<uw$8AJYkaU].HFn1kT[tx*-VAZ8usSKXcEKZ[wx:F8vYuR-b?tFFk1eM2RXs9yuu5dakz7r/{!AW9/(hK0]knHS&Q]!@K=ahmGr1Dbjb5(XE1UT%Ab@8rXvYop}$")
b = Term.regex("[a-z]+")

r1 = client.get_pattern(a)
print(r1) # deabc

r2 = client.get_pattern(b)
print(r2) # [a-z]+
```
</CodeTabs.Tab>
</CodeTabs>

## Visualizing a Term

A Term can also be rendered as a [Graphviz DOT](https://graphviz.org/doc/info/lang.html) description of its automaton. This is a debugging aid: paste the output into any Graphviz renderer to see the states and transitions behind a language that has become hard to read as a pattern.

<CodeTabs defaultValue="java">
<CodeTabs.Tab value="java" label="Java">
```java
String dot = client.getDot(Term.regex("[a-z]"));

System.out.println(dot);
// digraph Automaton {
//     rankdir = LR;
//     0    [shape=circle,label="0"];
//     initial [shape=plaintext,label=""];
//     initial -> 0
//     0 -> 1 [label="[a-z]"]
//     1    [shape=doublecircle,label="1"];
// }
```
</CodeTabs.Tab>

<CodeTabs.Tab value="javascript" label="JavaScript">
```javascript
const dot = await client.getDot(Term.regex("[a-z]"));

console.log(dot);
// digraph Automaton {
//     rankdir = LR;
//     0    [shape=circle,label="0"];
//     initial [shape=plaintext,label=""];
//     initial -> 0
//     0 -> 1 [label="[a-z]"]
//     1    [shape=doublecircle,label="1"];
// }
```
</CodeTabs.Tab>

<CodeTabs.Tab value="python" label="Python">
```python
dot = client.get_dot(Term.regex(r"[a-z]"))

print(dot)
# digraph Automaton {
#     rankdir = LR;
#     0    [shape=circle,label="0"];
#     initial [shape=plaintext,label=""];
#     initial -> 0
#     0 -> 1 [label="[a-z]"]
#     1    [shape=doublecircle,label="1"];
# }
```
</CodeTabs.Tab>
</CodeTabs>

## Matching strings locally

Every Term has a `matches` method that checks whether a given string belongs to its language. It runs **locally**, with no API call.

`matches` needs the regex pattern of the Term. A Term created with `regex` already has it. A Term created with `fair`, or returned by an operation in FAIR format, does not have it yet. In that case, call `getPattern` (or `get_pattern`) once to resolve and cache the pattern, then `matches` can be called as many times as you want.

If you call `matches` on a Term whose pattern is not resolved yet, it throws an error.

<CodeTabs defaultValue="java">
<CodeTabs.Tab value="java" label="Java">
```java
RegexSolverClient client = RegexSolverClient.builder()
    .apiToken(System.getenv("REGEXSOLVER_API_TOKEN"))
    .build();

Term term = Term.regex("[a-z]+");

term.matches("abc"); // true
term.matches("ABC"); // false

// A Term built from FAIR has no pattern yet
Term fairTerm = Term.fair("<uw$8AJYkaU].HFn1kT[tx*-VAZ8usSKXcEKZ[wx:F8vYuR-b?tFFk1eM2RXs9yuu5dakz7r/{!AW9/(hK0]knHS&Q]!@K=ahmGr1Dbjb5(XE1UT%Ab@8rXvYop}$");

client.getPattern(fairTerm); // resolves and caches the pattern
fairTerm.matches("deabc"); // true
```
</CodeTabs.Tab>

<CodeTabs.Tab value="javascript" label="JavaScript">
```javascript
const client = new RegexSolverClient({ apiToken: process.env.REGEXSOLVER_API_TOKEN });

const term = Term.regex('[a-z]+');

term.matches('abc'); // true
term.matches('ABC'); // false

// A Term built from FAIR has no pattern yet
const fairTerm = Term.fair("<uw$8AJYkaU].HFn1kT[tx*-VAZ8usSKXcEKZ[wx:F8vYuR-b?tFFk1eM2RXs9yuu5dakz7r/{!AW9/(hK0]knHS&Q]!@K=ahmGr1Dbjb5(XE1UT%Ab@8rXvYop}$");

await client.getPattern(fairTerm); // resolves and caches the pattern
fairTerm.matches('deabc'); // true
```
</CodeTabs.Tab>

<CodeTabs.Tab value="python" label="Python">
```python
client = RegexSolverClient(api_token=os.getenv("REGEXSOLVER_API_TOKEN"))

term = Term.regex(r"[a-z]+")

term.matches("abc")  # True
term.matches("ABC")  # False

# A Term built from FAIR has no pattern yet
fair_term = Term.fair("<uw$8AJYkaU].HFn1kT[tx*-VAZ8usSKXcEKZ[wx:F8vYuR-b?tFFk1eM2RXs9yuu5dakz7r/{!AW9/(hK0]knHS&Q]!@K=ahmGr1Dbjb5(XE1UT%Ab@8rXvYop}$")

client.get_pattern(fair_term)  # resolves and caches the pattern
fair_term.matches("deabc")  # True
```
</CodeTabs.Tab>
</CodeTabs>
