技术问询:如何生成符合美国电话号码格式的所有可能匹配片段数组
Hey there! Let's break down how to solve this problem step by step. I understand you need to generate all possible US phone number format fragments from a short digit string to use with react-highlight-words, and regex alone might not cut it here. Here's a practical code-based solution:
We need to generate every substring of the US phone number template (XXX) XXX-XXXX where, when you strip out non-digit characters, you're left exactly with the input digit string. For example, input "54" should produce fragments like "(54", "54)", "5) 4", etc.
First, we'll create a function that generates these fragments by combining:
- Generating valid combinations of digit positions from the template
- Creating all valid substrings around those positions
- Replacing template placeholders with the input digits
// Helper: Generate all k-length combinations from an array (in order) function getCombinations(arr, k) { const result = []; const backtrack = (start, current) => { if (current.length === k) { result.push([...current]); return; } for (let i = start; i < arr.length; i++) { current.push(arr[i]); backtrack(i + 1, current); current.pop(); } }; backtrack(0, []); return result; } // Main function to generate phone fragments function generatePhoneFragments(digitString) { const PHONE_TEMPLATE = "(XXX) XXX-XXXX"; // Get indices of all digit placeholders (X) in the template const DIGIT_POSITIONS = [...PHONE_TEMPLATE] .map((char, idx) => char === 'X' ? idx : null) .filter(pos => pos !== null); const n = digitString.length; if (n === 0 || n > 10) return []; // Get all valid combinations of n digit positions (in order) const digitPositionCombos = getCombinations(DIGIT_POSITIONS, n); const fragments = new Set(); // Use Set to avoid duplicates for (const positions of digitPositionCombos) { const firstDigitPos = positions[0]; const lastDigitPos = positions[positions.length - 1]; // Calculate valid start range: no extra digits before first selected digit const prevDigitIndex = DIGIT_POSITIONS.indexOf(firstDigitPos) - 1; const minStart = prevDigitIndex >= 0 ? DIGIT_POSITIONS[prevDigitIndex] + 1 : 0; const maxStart = firstDigitPos; // Calculate valid end range: no extra digits after last selected digit const nextDigitIndex = DIGIT_POSITIONS.indexOf(lastDigitPos) + 1; const maxEnd = nextDigitIndex < DIGIT_POSITIONS.length ? DIGIT_POSITIONS[nextDigitIndex] - 1 : PHONE_TEMPLATE.length - 1; const minEnd = lastDigitPos; // Generate all possible substrings for this position combination for (let start = minStart; start <= maxStart; start++) { for (let end = minEnd; end <= maxEnd; end++) { const templateSubstr = PHONE_TEMPLATE.slice(start, end + 1); // Map template digit positions to input string indices const digitMap = new Map(); positions.forEach((pos, idx) => digitMap.set(pos, idx)); // Replace template Xs with input digits const fragment = [...templateSubstr].map((char, substrIdx) => { const originalPos = start + substrIdx; return char === 'X' ? digitString[digitMap.get(originalPos)] : char; }).join(''); fragments.add(fragment); } } } return Array.from(fragments); }
Pass the generated fragments directly to the searchWords prop:
import Highlighter from 'react-highlight-words'; function PhoneNumberHighlighter({ text, currentInput }) { const searchFragments = generatePhoneFragments(currentInput); return ( <Highlighter highlightClassName="bg-yellow-200" // Your custom highlight style searchWords={searchFragments} autoEscape={true} textToHighlight={text} /> ); }
- Combination Generation: We use backtracking to find all valid sequences of digit positions in the template (e.g., for input length 2, we pair positions like [1,2], [3,6], [8,10], etc.).
- Valid Substring Ranges: We ensure no extra digit placeholders are included in the substring, so stripping non-digits will always match the input string.
- Deduplication: Using a
Setensures we don't have duplicate fragments (e.g., the plain digit string might be generated from multiple position combinations).
Testing this with input "54" will produce all the fragments from your example, plus any other valid ones like "54) " or "(54 " if needed.
内容的提问来源于stack exchange,提问作者Adam Dobrzeniewski

