library(readr)
library(dplyr)
library(tibble)
library(tidyr)
library(purrr)
library(stringr)
library(hunspell)
sentences <- read_csv(
"data/workforce/workforce_sentences.csv",
na = character(),
col_types = cols(
sentence_id = col_character(),
document_id = col_character(),
source_line = col_character(),
text = col_character(),
reference_label = col_character(),
uncertainty = col_character(),
annotator_id = col_character(),
rationale = col_character(),
codebook_version = col_character(),
codebook_hash = col_character(),
derived = col_character(),
transformation = col_character()
)
)
all_caps_pattern <- "\\b[A-Z]{2,}\\b"
all_caps_hits <- sentences |>
transmute(
sentence_id,
text,
token = str_extract_all(text, all_caps_pattern)
) |>
unnest(token)Finding abbreviations without trusting capitals
Compare all-capital tokens with parenthetical definitions
The Riverton Workforce Lab needs links between short forms and their long forms. One simple rule finds all-capital tokens as possible abbreviations.
The flyer shows a limitation of that rule. Its capitalized headings reflect formatting, not necessarily abbreviated meanings.
The author created the fictional Riverton Workforce Lab, its job board, and its training flyer for teaching.
In this lesson, you will practice how to:
- find all-capital tokens with a regular expression.
- examine capitalised heading matches.
- measure what a dictionary-and-length guard removes.
- find
Long Form (SHORT)definitions. - separate real data from constructed examples.
Find all-capital tokens
The setup reads the text file, expands regex matches, and compares words with hunspellβs dictionary. The stringr package uses the ICU regex engine. The [A-Z] range nevertheless covers only ASCII capitals. It will not match a token such as ΓCOLE.
| Sentence ID | Text | All-capital token |
|---|---|---|
| s023 | RIVERTON SKILLS OPEN HOUSE | RIVERTON |
| s023 | RIVERTON SKILLS OPEN HOUSE | SKILLS |
| s023 | RIVERTON SKILLS OPEN HOUSE | OPEN |
| s023 | RIVERTON SKILLS OPEN HOUSE | HOUSE |
| s024 | DATA SUPPORT CERTIFICATE | DATA |
| s024 | DATA SUPPORT CERTIFICATE | SUPPORT |
| s024 | DATA SUPPORT CERTIFICATE | CERTIFICATE |
An abbreviation is a shortened written form, such as Dr. or approx.. An initialism uses initial letters pronounced separately, as in NLP. An acronym uses initial letters pronounced as a word, as in NATO. This rule detects none of those categories directly. It finds sequences of two or more ASCII capitals, which sometimes correspond to abbreviations.
Here it finds 7 tokens from RIVERTON SKILLS OPEN HOUSE and DATA SUPPORT CERTIFICATE. Neither heading contains a genuine short-form abbreviation.
Score and guard the capital rule
The lesson author examined every all-capital hit in the Riverton text and found no short-form abbreviations. The guard below keeps only tokens that are five characters or shorter and absent from the dictionary.
scored_caps <- all_caps_hits |>
mutate(
true_abbreviation = FALSE,
token_lower = str_to_lower(token),
in_dictionary = hunspell_check(token_lower),
longer_than_five = str_length(token) > 5L,
guarded_match = !longer_than_five & !in_dictionary,
removal_reason = case_when(
in_dictionary & longer_than_five ~ "dictionary word; longer than five",
in_dictionary ~ "dictionary word",
longer_than_five ~ "longer than five",
TRUE ~ "kept"
)
)
capital_score <- tibble(
rule = c("all-capital token", "short and not in dictionary"),
candidates = c(nrow(scored_caps), sum(scored_caps$guarded_match)),
hand_rejected = c(
sum(!scored_caps$true_abbreviation),
sum(scored_caps$guarded_match & !scored_caps$true_abbreviation)
),
true_abbreviations_found = c(
sum(scored_caps$true_abbreviation),
sum(scored_caps$guarded_match & scored_caps$true_abbreviation)
)
)
guard_details <- scored_caps |>
select(sentence_id, token, in_dictionary, longer_than_five, guarded_match, removal_reason)
guard_failure_examples <- tibble(token = c("UNESCO", "IT")) |>
mutate(
token_lower = str_to_lower(token),
in_dictionary = hunspell_check(token_lower),
longer_than_five = str_length(token) > 5L,
guarded_match = !longer_than_five & !in_dictionary
)| Rule | Candidates kept | Hand-rejected hits | True abbreviations found |
|---|---|---|---|
| all-capital token | 7 | 7 | 0 |
| short and not in dictionary | 0 | 0 | 0 |
| Sentence ID | Token | In dictionary | Longer than five | Kept by guard | Removal reason |
|---|---|---|---|---|---|
| s023 | RIVERTON | FALSE | TRUE | FALSE | longer than five |
| s023 | SKILLS | TRUE | TRUE | FALSE | dictionary word; longer than five |
| s023 | OPEN | TRUE | FALSE | FALSE | dictionary word |
| s023 | HOUSE | TRUE | FALSE | FALSE | dictionary word |
| s024 | DATA | TRUE | FALSE | FALSE | dictionary word |
| s024 | SUPPORT | TRUE | TRUE | FALSE | dictionary word; longer than five |
| s024 | CERTIFICATE | TRUE | TRUE | FALSE | dictionary word; longer than five |
| Token | Lowercase token | In dictionary | Longer than five | Kept by guard |
|---|---|---|---|---|
| UNESCO | unesco | FALSE | TRUE | FALSE |
| IT | it | TRUE | FALSE | FALSE |
The guard keeps zero candidates. It removes 7 hand-rejected heading words and finds 0 abbreviations. Removing every match does not establish a good filter. Six tokens are dictionary words, and four exceed five characters. Only the length limit removes RIVERTON.
The guard also rejects UNESCO because of its length. It rejects IT because the dictionary contains it. Results depend on the hunspell dictionary available at execution time.
Find parenthetical definitions
The Riverton text has no Long Form (SHORT) examples. This section uses a short author-created passage solely to demonstrate the pattern.
In the code, \(match_table, current_sentence_id) is R shorthand for a small function that handles one sentenceβs match table and ID.
definition_pattern <- regex(
"\\b((?:[A-Z][a-z]+\\s+){1,}[A-Z][a-z]+)\\s*\\(([A-Z]{2,})\\)"
)
extract_definitions <- function(text, sentence_id) {
match_tables <- str_match_all(text, definition_pattern)
pieces <- map2(match_tables, sentence_id, \(match_table, current_sentence_id) {
if (nrow(match_table) == 0L) {
return(tibble(
sentence_id = character(),
long_form = character(),
short_form = character()
))
}
tibble(
sentence_id = current_sentence_id,
long_form = str_squish(match_table[, 2]),
short_form = match_table[, 3]
)
})
list_rbind(pieces)
}
riverton_definitions <- extract_definitions(sentences$text, sentences$sentence_id)
riverton_parenthetical_score <- tibble(
source = "Riverton text",
definitions_found = nrow(riverton_definitions)
)
constructed_passage <- tibble(
sentence_id = c("c001", "c002"),
text = c(
"The note defines Natural Language Processing (NLP) for the workshop.",
"The class lists a Data Support Certificate (DSC) for applicants."
)
)
definitions <- extract_definitions(
constructed_passage$text,
constructed_passage$sentence_id
)
shape_only_example <- extract_definitions(
"Riverton Skills Centre (NLP)",
"c003"
)
parenthetical_score <- tibble(
true_definitions_in_constructed_passage = 2L,
definitions_found = nrow(definitions)
)| Source | Definitions found |
|---|---|
| Riverton text | 0 |
| Sentence ID | Long form | Short form |
|---|---|---|
| c001 | Natural Language Processing | NLP |
| c002 | Data Support Certificate | DSC |
| True definitions in constructed passage | Definitions found |
|---|---|
| 2 | 2 |
The parenthetical pattern finds zero Riverton definitions. It finds Natural Language Processing (NLP) and Data Support Certificate (DSC) in the constructed passage. That passage contains only positive cases. The result cannot measure false matches or missed definitions.
The pattern matches capitalised words followed by parenthesized capitals. It does not compare the short-form letters with the long form. Thus Riverton Skills Centre (NLP) also matches. The Schwartz and Hearst algorithm listed under Sources examines those letter links and accepts lowercase long forms. This lessonβs rule performs fewer checks.
What to remember
- All-capital text is only a rough short-form signal.
- The 7 capital-letter hits in the Riverton headings contain 0 abbreviations.
- Keeping 0 of 7 matches does not establish that the guard preserves abbreviations.
- The parenthetical rule finds 2 constructed positive cases and 0 Riverton definitions.
- Parenthetical shape rules need an additional check of short-form letters against the long form.
Reject the all-capital rule for these flyer headings. For future text, retain candidate short forms during rule evaluation. Evaluate both examples and counter-examples before accepting the rule.