diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d9a5a6b402..2c42c7a408 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,11 @@ Next release ``licensedcode-data``. https://github.com/aboutcode-org/scancode-toolkit/pull/5056 +- Fix author detection to recognize an ``Author:`` tag glued directly + to a name with no space, and a first/last name joined by a dot such + as ``Author:Frankie.Chu``. + https://github.com/aboutcode-org/scancode-toolkit/issues/4229 + v33.0.0rc1 - 2026-05-14 ------------------------ diff --git a/src/cluecode/copyrights.py b/src/cluecode/copyrights.py index 6d17467acf..0ebb3ba370 100644 --- a/src/cluecode/copyrights.py +++ b/src/cluecode/copyrights.py @@ -392,7 +392,13 @@ def detect(self, yield author -def get_tokens(numbered_lines, splitter=re.compile(r'[\t =;]+').split): +def get_tokens( + numbered_lines, + splitter=re.compile(r'[\t =;]+').split, + author_tag=re.compile(r'^([Aa]uthors?):(\S+)$').match, + author_name=re.compile(r'^[Aa]uthors?$').match, + dot_joined_name=re.compile(r'^([A-Z][a-z]+)\.([A-Z][a-z]+)(,?)$').match, +): """ Return an iterable of pygmars.Token built from a ``numbered_lines`` iterable of tuples of (line number, text). @@ -400,6 +406,7 @@ def get_tokens(numbered_lines, splitter=re.compile(r'[\t =;]+').split): We perform a simple tokenization on spaces, tabs and some punctuation: =; """ last_line = "" + last_token = "" for start_line, line in numbered_lines: pos = 0 @@ -440,10 +447,32 @@ def get_tokens(numbered_lines, splitter=re.compile(r'[\t =;]+').split): .strip() ) + # split a leading Author/Authors tag glued to a name with no + # space in between, e.g. "Author:Frankie.Chu", into two tokens + tag_match = author_tag(tok) + if tag_match: + tag, name = tag_match.groups() + yield Token(value=tag, start_line=start_line, pos=pos) + pos += 1 + last_token = tag + tok = name + + # split a first/last name joined by a dot right after an + # Author/Authors tag, e.g. "Author: Frankie.Chu" or the glued + # "Author:Frankie.Chu", into two separate name tokens + if tok and author_name(last_token): + name_match = dot_joined_name(tok) + if name_match: + first_name, last_name, trailing_comma = name_match.groups() + yield Token(value=first_name, start_line=start_line, pos=pos) + pos += 1 + tok = last_name + trailing_comma + # the tokenizer allows a single colon or dot to be a token and we discard these if tok and tok not in ':.': yield Token(value=tok, start_line=start_line, pos=pos) pos += 1 + last_token = tok class Detection: diff --git a/tests/cluecode/data/authors/author_dot_joined_name-TM1637_cpp.cpp b/tests/cluecode/data/authors/author_dot_joined_name-TM1637_cpp.cpp new file mode 100644 index 0000000000..3a5db67217 --- /dev/null +++ b/tests/cluecode/data/authors/author_dot_joined_name-TM1637_cpp.cpp @@ -0,0 +1,2 @@ +// Date:9 April,2012 +// Author:Frankie.Chu diff --git a/tests/cluecode/data/authors/author_dot_joined_name-TM1637_cpp.cpp.yml b/tests/cluecode/data/authors/author_dot_joined_name-TM1637_cpp.cpp.yml new file mode 100644 index 0000000000..220ee3963c --- /dev/null +++ b/tests/cluecode/data/authors/author_dot_joined_name-TM1637_cpp.cpp.yml @@ -0,0 +1,8 @@ +what: + - authors + - authors_summary +authors: + - Frankie Chu +authors_summary: + - value: Frankie Chu + count: 1