The Count Occurrences tool scans up to one million characters of pasted text for a single literal search string and returns both the total number of matches and the first 100 zero-based starting positions, all in one pass inside the browser. That scale matters for "bulk" work because exported logs, scraped article archives, merged CSV columns, and long transcripts easily cross the size threshold where manual scanning or spreadsheet formulas stop being practical. Because matching is literal rather than regular-expression based, a period matches a period and an asterisk matches an asterisk, so punctuation inside the search string never needs escaping. Searching for user_id= inside a 400 KB access log, TODO inside a merged codebase export, or a repeated separator inside a CSV column all use the same three-step flow. All of the counting, lowercasing, and position collection runs locally in the page, so sensitive logs or unreleased document drafts can be counted without being uploaded to any server.

count occurrences bulk
Count Occurrences in Bulk Text Locally in Your Browser

What "bulk" actually means for a text counter

For a spreadsheet, "bulk" usually means a column with thousands of cells. For a text counting tool, "bulk" means something else: a single pasted block that can be hundreds of kilobytes or several hundred thousand characters long, where the search string might appear thousands of times. Count Occurrences is built for that second definition. The source field accepts up to 1,000,000 characters, and the search field accepts up to 1,000 characters, including spaces, tabs, pasted line breaks, emoji, and ordinary Unicode text. The reported total count is never truncated, so even when there are 87,342 matches in a million-character transcript, the headline number still reflects every hit. Only the position preview is capped, at the first 100 zero-based offsets, so that the page stays usable when a result would otherwise print tens of thousands of lines.

This separation between a precise total and a bounded preview is the core bulk design choice. It means a content team checking how often a product name appears in a year of blog posts gets an exact percentage calculation, while a code reviewer hunting the first few console.log call sites in a 600 KB JavaScript bundle gets a navigable list to jump to the first handful of hits. Neither task forces the other to over-render.

How to run a bulk occurrence count

  1. Paste or type the source text into the main input field. The field accepts up to one million characters of any Unicode the browser can render, including newlines, tabs, and emoji.
  2. Enter the literal text to find in the search field. Choose case-sensitive matching when capitalization matters, or case-insensitive matching when "Error" and "ERROR" should count as the same string.
  3. Decide whether matches may overlap. Keep the default non-overlap mode for ordinary replacements, or switch on overlap mode when you want every possible run to count, including repeated substrings.
  4. Read the total count at the top of the result panel, then scroll through the listed positions. The first 100 zero-based offsets are shown in order; the total above them is exact.

Editing either input or changing any option clears the old output automatically, so a stale count from a previous run cannot be mistaken for the current settings. For deeper automation across many queries against the same file, the same deterministic logic is available through the Count Occurrences tool, which keeps the same literal-matching, English-locale lowercasing, and bounded preview behavior every time.

Choosing between overlap and non-overlap modes

The overlap toggle is the single most important decision for a bulk count, because the same search string inside the same source text can produce two different totals depending on which mode is selected. The tool exposes both interpretations explicitly instead of guessing, so the answer matches the question being asked.

Search in source Mode Advance per match Positions returned for "aa" inside "aaaa" Total count
aaaa Non-overlap Past the full matched length (2 units) 0, 2 2
aaaa Overlap One JavaScript string unit 0, 1, 2 3

Non-overlap mode advances past the entire matched search string after every hit, which mirrors how a simple literal replace operation would behave in code. Overlap mode advances only one JavaScript string unit, which is the right setting for sequence analysis — counting runs of repeated characters, tandem repeats in DNA-style strings, or any case where every possible starting offset is a meaningful observation. Switching the toggle re-runs the count against the same input, so the difference between the two answers is always attributable to the option, never to a hidden default.

Case sensitivity and what English-locale folding does and does not

Case-sensitive mode compares the entered strings byte for byte, so "Error" and "ERROR" are distinct matches with their own totals. Case-insensitive mode converts both the source text and the search string with the English-locale lowercase routine before running the comparison, while still reporting offsets from the original text. That matters in bulk: a 200 KB server log counted case-insensitively for "fail" returns every "FAIL", "Fail", and "fail" hit at the position where the original casing appears.

The English-locale lowercasing is a practical shortcut, not a full collation engine. Locale-specific equivalence rules beyond English, normalization between composed and decomposed Unicode forms, accent folding, and script-specific case mappings are not inferred. For a French-language document where "é" and "e" need to count as the same letter, or for a German corpus where "ß" should match "ss", a separate preprocessing step is needed before the paste. The tool never modifies the source text itself — no trimming, no line-ending changes, no whitespace collapsing, no duplicate removal — so the input can be reused unchanged after the count.

Reading the position list when the count runs into the hundreds

Once a count crosses a few dozen matches, the position preview becomes the most useful part of the result. The positions are zero-based JavaScript string offsets, which means the first character of the source text is position 0, the second is position 1, and so on. For most ordinary English text, one character equals one offset. Characters represented by surrogate pairs — many emoji, some rare CJK code points, certain mathematical symbols — consume two UTF-16 code units per perceived character, which is why an emoji can shift every following position number by one. The displayed offsets are intended for reproducible browser and programming work, not as user-perceived grapheme indexes, and that distinction is most visible in a long, emoji-heavy transcript.

The cap of 100 displayed positions is deliberate: a result with several hundred thousand matches would otherwise freeze the tab while trying to render. The total above the list is exact regardless of the cap, so percentage calculations and totals stay trustworthy. A zero result is treated as a valid answer and simply shows no positions, which is the right behavior for sanity checks like "does this transcript actually contain the word 'lambda' anywhere".

Limits and when a different text tool fits better

The bulk design of Count Occurrences has hard edges worth knowing about. The search field rejects an empty string, because an empty match would otherwise fire at every boundary in the source text and return an ambiguous count. A search string longer than the remaining source naturally returns zero. There is no whole-word mode, no fuzzy matching, no stemming, no wildcard syntax, no Unicode normalization, no replacement action, and no file-upload parser — by design, because adding those would silently change what a "count" means. For counts by word rather than by a specific string, the Word Counter tool is the right fit. For changing matches instead of just counting them, Find and Replace Text handles the same literal-matching model and adds the substitution step. For bulk editing across many literal matches at once, the workflow described in this guide to bulk local text replacement extends the same engine into replacement. For comparing two bodies of text rather than counting one substring inside another, a line-based diff is the better tool.

The operating contract for every run is the same: deterministic for the same browser string inputs and the same option settings, with no network call, no randomness, no external table, and no server state involved. That determinism is what makes a bulk count reproducible across team members and across re-runs, and it is what allows the total to be trusted even when only the first 100 positions are shown on screen.

For a deeper look, see Email Address Finder: Extract From Pasted Text Locally.