如何在R语言中精准匹配指定手机号模式并实现高效脱敏?
Hey there! Let's work through your phone number masking and pattern matching challenges together.
The issue with your original pattern2 is two-fold: the . in regex matches any character (not just a literal dot), and there's no boundary check to prevent partial matches from non-phone text like your year sequence. Here's how to fix it:
We'll create targeted regex patterns that:
- Match only valid phone number structures (either with consistent separators or plain 11-digit numbers)
- Use word boundaries (
\\b) to avoid grabbing partial digits from other text
library(stringr) # Your sample data x = c("010-1234-5678", "John 010-8888-8888", "Phone: 010-1111-2222", "Peter 018.1111.3333", "Year(2007,2019,2020)", "Alice 01077776666") df = data.frame(phoneNumber = x) # Pattern 1: Matches phone numbers with consistent separators (either - or .) # \\b ensures we don't match partial digits; \\1 enforces the same separator throughout pattern_separated <- "\\b\\d{3}([-.])\\d{4}\\1\\d{4}\\b" # Pattern 2: Matches plain 11-digit phone numbers pattern_plain <- "\\b\\d{11}\\b" # Extract all valid phone numbers valid_phones <- c( str_match_all(df$phoneNumber, pattern_separated) %>% unlist(), str_match_all(df$phoneNumber, pattern_plain) %>% unlist() ) # Check the result - no more year sequence matches! valid_phones
Running this will give you only the actual phone numbers:
[1] "010-1234-5678" "010-8888-8888" "010-1111-2222" "018.1111.3333" "01077776666"
Your for-loop works, but it's inefficient for large datasets (it modifies the entire column once per phone number). Instead, we can use str_replace_all to handle all replacements in one go, and even preserve the original number's format if needed:
Option 1: Replace all with a fixed masked number
If you want all masked numbers to look identical regardless of original format:
# Combine both patterns into one for a single pass combined_pattern <- paste0("(", pattern_separated, "|", pattern_plain, ")") df$masked_phone <- str_replace_all(df$phoneNumber, combined_pattern, function(match) { # Return the appropriate masked format based on original if (str_detect(match, "[-.]")) "010-9999-9999" else "01099999999" })
Option 2: Preserve original separator format
If you want to keep the original - or . while masking the digits:
# Mask separated numbers (keep the separator) df$masked_phone <- str_replace_all(df$phoneNumber, "\\b(\\d{3})([-.])(\\d{4})\\2(\\d{4})\\b", "\\1\\29999\\29999") # Mask plain 11-digit numbers df$masked_phone <- str_replace_all(df$masked_phone, "\\b(\\d{3})(\\d{8})\\b", "\\199999999")
This will result in masked numbers that match the original structure (e.g., 018.9999.9999 instead of forcing a - separator).
内容的提问来源于stack exchange,提问作者Inho Lee

