import re


def count_lines_with_wrapping(s, linewidth=80, tabwidth=8):
    """Count the number of lines in a given string.

    Lines are counted as if the string was wrapped so that lines are never over
    linewidth characters long.

    Tabs are considered tabwidth characters long.
    """
    pos = 0
    linecount = 1
    current_column = 0

    for m in re.finditer(r"[\t\n]", s):
        # process the normal chars up to tab or newline
        numchars = m.start() - pos
        pos += numchars
        current_column += numchars

        # deal with tab or newline
        if s[pos] == '\n':
            linecount += 1
            current_column = 0
        else:
            assert s[pos] == '\t'
            current_column += tabwidth - (current_column % tabwidth)

            # if a tab passes the end of the line, consider the entire tab as
            # being on the next line
            if current_column > linewidth:
                linecount += 1
                current_column = tabwidth

        pos += 1 # after the tab or newline

        # avoid divmod(-1, linewidth)
        if current_column > 0:
            # If the length was exactly linewidth, divmod would give (1,0),
            # even though a new line hadn't yet been started. The same is true
            # if length is any exact multiple of linewidth. Therefore, subtract
            # 1 before doing divmod, and later add 1 to the column to
            # compensate.
            lines, column = divmod(current_column - 1, linewidth)
            linecount += lines
            current_column = column + 1

    # process remaining chars (no more tabs or newlines)
    current_column += len(s) - pos
    # avoid divmod(-1, linewidth)
    if current_column > 0:
        linecount += (current_column - 1) // linewidth
    else:
        # the text ended with a newline; don't count an extra line after it
        linecount -= 1

    return linecount