Line Counter
Total, non-empty, and blank lines — live as you paste. Built for the things people actually count lines in: source files, log excerpts, CSV exports, and word lists. Nothing you paste leaves your browser.
What counts as a line — the rules, stated
Line counting looks trivial until the edge cases, so this page fixes three conventions and
names them. First, lines split on newline characters, with Windows CRLF pairs and lone
carriage returns normalized to a single break beforehand, so the platform the text came from
cannot change the count. Second, a trailing newline terminates the last line instead of adding
a phantom empty one — the 4-character text
a↵b↵ is 2 lines, exactly what wc -l
reports for a file with a final newline. Third, a line containing only spaces or tabs is counted,
but counted as blank: a↵b↵↵c is 4
lines — 3 non-empty and 1 blank — and the two figures always
sum to the total, so nothing is silently dropped or double-counted. Every line, character and paragraph
figure in the text below is computed at build time by the same engine the counter above runs on
your text, so the prose and the tool cannot disagree. How lines relate to the other two structural
units this site counts is the subject of the
guide to sentences, paragraphs, and lines; this page stays on lines.
How the count is produced, step by step
The engine does four things in order, and every result on this page follows from them. It first rewrites each carriage-return-plus-line-feed pair, and each carriage return standing alone, as a single line feed. It then splits the text at every line feed, which yields one piece per line plus — whenever the text ends in a line feed — one empty piece after it. If that final piece is empty and is not the only piece, it is discarded: that single step is the trailing-newline rule. Finally each remaining piece is classified: a piece with at least one non-whitespace character is non-empty, and anything else is blank. Total lines is the number of pieces; the other two figures partition it. Empty text short-circuits before any of this and reports 0 lines, which is why the counter reads zero before you paste anything. There is no sampling and no approximation: the whole text is re-split on every keystroke, up to the engine's two-million-character limit, beyond which it reports an explicit message rather than a wrong number.
CRLF, CR, LF — and files that mix them
Three conventions mark the end of a line: a line feed alone (LF), a carriage return followed
by a line feed (CRLF) — the Windows pair — and a lone carriage return (CR). This page treats
all three as one break. A counter that split only on line feeds would report a CR-only file as
a single enormous line, and a counter that split on both characters independently would count
every CRLF pair twice. Normalizing first avoids both errors. Written out with ␍ for a carriage
return and ↵ for a line feed, the same 3-line text arrives as first↵second↵third, first␍↵second␍↵third, or
first␍second␍third, and this page reports 3, 3, and
3 lines respectively — one figure, three encodings. A file with mixed endings, which
happens when it has been edited on more than one platform, falls under the same rule:
first␍↵second↵third␍fourth is 4 lines.
The one place the ending convention still shows through is the Characters figure. That count is Unicode code points, and a carriage return is a code point like any other, so the LF version of the text above is 18 characters while the CRLF version is 20: identical lines, different length. If a form or a length limit rejects text that "fits" by the line count, invisible terminators are the first thing to check; the character counter covers the rest of that ground.
The trailing newline, and where wc -l agrees
Editors and command-line tools quietly disagree about whether a file's last line needs a
terminator, which is why a stated rule matters. Under the POSIX definition a line is a
sequence of characters ended by a newline — so a file whose every line is complete ends with
one — and wc -l literally counts newline characters. On such text, with LF or CRLF
endings, this page and wc -l agree exactly: a↵b↵
is 2 lines under both, because the last newline closes the second line rather
than opening a third. The rule absorbs exactly one terminator, not every trailing break: a↵b↵↵ is
3 lines — 2 non-empty and
1 blank — because once the final line feed is consumed, an empty line
genuinely remains. A text consisting of a single line feed and nothing else is
1 line, classified blank, which again matches the newline count.
There are two honest divergences. The first is the unterminated last line.
a↵b has no final newline; this page counts it as
2 lines, the same as the terminated version, because the second line is visibly
there — it is what you would mean if asked how many lines the text has. A strict newline count does
not count that unterminated line at all, so wc -l reports a smaller figure for a file
whose final line is missing its terminator. The second is the lone carriage return from the section
above: this page normalizes it to a line break, while a strict newline count finds no line feed
in a CR-only text and so does not split it at all — first␍second␍third is
3 lines here and one unbroken run of characters to wc -l.
Practically: if the two disagree on a file, check whether the file ends with a newline, and
whether its breaks are carriage returns, before suspecting either tool.
Blank versus non-empty
A blank line is one whose content, after whitespace is stripped from both ends, is empty. The
test is the JavaScript trim rule, so it covers spaces, tabs, and the less visible whitespace
characters that rule recognizes — such as a non-breaking space that arrives via copy-paste.
Concretely, a text whose middle lines hold a run of spaces and then a single tab, alpha↵ ↵ ↵beta, is
4 lines: 2 non-empty and
2 blank. Replace the middle with a lone non-breaking space and the result
is 3 lines with 1 blank — the same classification. A line carrying
any visible character, whether a single punctuation mark, a closing brace, or a digit, is non-empty.
The two classes are exhaustive and exclusive, which is why non-empty plus blank equals the total
on every input; if you ever see otherwise it is a bug, and the
contact page is the place to report it.
Note the relationship with paragraphs. A blank line is exactly what separates paragraphs under
the plain-text convention the paragraph counter
uses, while a single line break does not split one. So a↵b↵↵c is
4 lines but 2 paragraphs, and the blank-line figure here is a close
cousin of the paragraph count: each blank run is a paragraph boundary, though several consecutive
blank lines form only one boundary.
Counting code
For source code, the non-empty figure is the closest thing to a quick size estimate — blank lines are formatting, not content. Take a short original snippet, saved with the customary final newline:
function total(items) {
// running total of item prices
let sum = 0;
for (const item of items) {
sum += item.price;
}
return sum;
}
function average(items) {
return items.length ? total(items) / items.length : 0;
}
It is 12 lines, of which 11 are non-empty and 1 is the blank separator between the two functions. The comment line is among the non-empty ones, which is the first thing to know about the limits of this figure: it is not a source-lines-of-code metric. Comments count, a closing brace on its own line counts, and one dense line can hold what another style spreads over several. Language-aware counters exist for that job; this page answers the faster question — roughly how big is the function about to go into a review, or how long did that generated file come to — without installing anything. Two details follow from the rules above. The final newline the snippet ends with is absorbed, so a file saved that way reports the number of lines you actually wrote, not one more. And indentation never affects the count: leading tabs or spaces belong to the line they sit on, so a deeply nested block is no more lines than a flat one.
Counting logs and data exports
For logs the total is usually the interesting number, since most log formats emit one event per line. An excerpt in which every event occupies exactly one line:
2026-09-26T08:00:01Z INFO server started 2026-09-26T08:00:02Z INFO listening on port 8080 2026-09-26T08:00:09Z WARN slow query took 412 ms 2026-09-26T08:00:10Z INFO cache warmed 2026-09-26T08:00:11Z INFO ready
reports 5 lines, and because nothing wraps, that is also the event count. The exception is any entry that continues onto indented lines, typically a stack trace:
2026-09-26T08:00:12Z ERROR request failed
at handler (app.js:42)
at run (app.js:10)
That is a single event but 3 lines. When an excerpt contains such entries, the event count is the line count minus the indented continuation lines, and the line counter cannot tell the two apart — it counts terminators, not meaning. The same arithmetic applies to delimited exports. A CSV with a header row —
id,name,qty 1,bolt,40 2,washer,120 3,nut,75
— is 4 lines, so it holds 3 data rows. One caveat: a quoted field that legitimately contains a line break would register as an extra line here, since the counter does not parse CSV quoting. Word lists and any other one-item-per-line file behave like the clean log: the total is the item count once blank lines are subtracted, and the blank figure gives you that subtraction directly.
What is not a line break here
Two things that look like line breaks are not counted as such, and both are deliberate. First,
the visual wrapping in the box above: a long line wraps to fit the width of the textarea, but
wrapping inserts no character, so however many screen rows a line occupies it remains one line
— the count depends on the text, never on the window size. Second, Unicode defines separator
characters beyond the line feed — LINE SEPARATOR (U+2028) and PARAGRAPH SEPARATOR (U+2029)
among them — and this page does not split on them:
one⟨LS⟩two⟨PS⟩three, with those two separators in place of ordinary breaks, is
1 line. That matches wc -l, which also does not treat them
as line breaks. If text pasted from a rich source reports fewer lines than you expect, those
characters are a likely cause; replacing them with ordinary line breaks in an editor before
counting gives the intended figure.
Lines, paragraphs, sentences — three different units
A line is a typographic unit: it ends where a terminator character sits, and it says nothing about grammar. A sentence ends at punctuation and can run across many lines or share one line with several others; a paragraph is a block bounded by blank lines and can be one line or many. The three counters on this site therefore answer three different questions about the same text, and it is normal for all three figures to differ. Verse and postal addresses are the clearest case: many lines, one paragraph, and however many sentences the punctuation says. This page counts only lines. The guide to sentences, paragraphs, and lines covers how the three units relate and where their counts diverge, and the other guides cover the site's remaining counters. For one-off comparisons the sentence counter and paragraph counter apply their rules directly.
Frequently asked questions
Does a trailing newline count as an extra line?
No. A newline at the very end of the text terminates the last line rather than opening an empty new one, so "a↵b↵" is 2 lines, not 3. This matches wc -l, POSIX's definition of a line, and what your editor's line numbers show for a file with a final newline.
How are Windows (CRLF) line endings handled?
CRLF pairs and lone carriage returns are each treated as a single line break before counting, so a file saved on Windows and the same file saved on Linux report identical line counts.
What counts as a blank line?
A line that is empty or contains only whitespace — spaces, tabs, and other characters JavaScript's trim rule treats as whitespace, such as a non-breaking space. A line holding even one visible character counts as non-empty. Total lines is always non-empty plus blank.
Does this page give the same number as wc -l?
Whenever the text ends with a newline and uses LF or CRLF line endings, yes — "a↵b↵" is 2 lines under both. There are two divergences. The first is text whose last line has no terminator: this page counts that visible last line, while wc -l counts newline characters and so leaves it out. The second is lone carriage returns: this page normalizes each one to a line break, while wc -l does not treat a carriage return as a line break at all, so "first␍second␍third" is 3 lines here and is not split there. If the two differ on a file, check for a missing final newline or for carriage-return line endings before suspecting either.
Do long lines that wrap in the box count as several lines?
No. The box wraps long lines to fit its width, but wrapping inserts no character into the text, so a line remains one line however many screen rows it occupies. Only actual line-break characters split lines.
Why is the character count higher than the text seems to need?
Line terminators are characters. Each line feed is one code point and each Windows CRLF pair is two, so the same lines can carry different character totals depending on where the text was saved: the 3-line sample on this page is 18 characters with LF endings and 20 with CRLF.
Is there a size limit?
The engine accepts up to two million characters per analysis and reports an explicit message, rather than a wrong count, when input exceeds that. Below the limit there is no sampling: the entire text is re-counted on every keystroke.
Is it safe to paste logs or config files here?
The counting is plain JavaScript running locally on a static page — nothing you paste is uploaded, logged, or stored, and the page keeps counting with your connection switched off. That said, the usual caution about pasting secrets anywhere still applies.
Counting happens locally in your browser — nothing you paste is transmitted or stored. For prose rather than code, the word counter, character counter, and paragraph counter are the right tools; the exact line rules live on the methodology page.