find_regex_position
Locate regex pattern matches in files by returning line and column positions for each occurrence, enabling precise text analysis and pattern identification.
Instructions
Find the positions (line and column) of regex pattern matches in a file. Returns an array of matches with their positions. Line and column numbers are 0-indexed (first line is 0). Each match includes: match (matched text), line (starting line), column (starting column), endLine (ending line), and endColumn (ending column, exclusive). IMPORTANT: The path parameter must be an absolute path. Relative paths are not supported.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to the file to search in. Relative paths are not supported. | |
| regex | Yes | Regular expression pattern to search for |
Implementation Reference
- src/index.ts:96-118 (handler)The handler case block for the 'find_regex_position' tool. It parses input arguments, validates the file path against allowed directories, calls the helper function to find regex positions, and returns the JSON-stringified results or an error.case "find_regex_position": { try { // Validate input const parsed = FindRegexPositionArgsSchema.parse(args); // Validate path for security const validatedPath = await validatePath(parsed.path, allowedDirectories); // Find regex positions const positions = await findRegexPositionsInFile(validatedPath, parsed.regex); return { content: [{ type: 'text', text: JSON.stringify(positions), }] }; } catch (error) { return { error: error instanceof Error ? error.message : String(error), }; } }
- src/index.ts:42-46 (schema)Zod schema defining the input arguments for the 'find_regex_position' tool: path (absolute file path) and regex (pattern string). Used for validation and JSON schema generation.// Schema definitions for the find_regex_position tool const FindRegexPositionArgsSchema = z.object({ path: z.string().describe("Absolute path to the file to search in. Relative paths are not supported."), regex: z.string().describe("Regular expression pattern to search for"), });
- src/index.ts:68-78 (registration)Tool registration in the ListToolsRequest handler, including name, detailed description, and input schema reference.{ name: "find_regex_position", description: "Find the positions (line and column) of regex pattern matches in a file. " + "Returns an array of matches with their positions. " + "Line and column numbers are 0-indexed (first line is 0). " + "Each match includes: match (matched text), line (starting line), column (starting column), " + "endLine (ending line), and endColumn (ending column, exclusive). " + "IMPORTANT: The path parameter must be an absolute path. Relative paths are not supported.", inputSchema: zodToJsonSchema(FindRegexPositionArgsSchema), },
- src/utils/regex-utils.ts:18-21 (helper)Helper function that reads the file content and delegates to findRegexPositionsInContent for processing. This is the entry point called by the handler.export async function findRegexPositionsInFile(filePath: string, regexStr: string): Promise<RegexMatchPosition[]> { const content = await fs.readFile(filePath, "utf-8"); return findRegexPositionsInContent(content, regexStr); }
- src/utils/regex-utils.ts:29-102 (helper)Core helper function that executes the regex search on content, calculates precise 0-indexed line/column positions for start and end of each match, and returns an array of RegexMatchPosition objects.export function findRegexPositionsInContent(content: string, regexStr: string): RegexMatchPosition[] { // Split content into lines for position calculation const lines = content.split("\n"); try { // Create regex with global flag to find all matches const regex = new RegExp(regexStr, "g"); const matches: RegexMatchPosition[] = []; let match: RegExpExecArray | null; // Process each match while ((match = regex.exec(content)) !== null) { const matchText = match[0]; const matchStartIndex = match.index; // Calculate line and column for start position let currentIndex = 0; let startLine = 0; let startColumn = 0; for (let i = 0; i < lines.length; i++) { const lineLength = lines[i].length + 1; // +1 for the newline character if (currentIndex + lineLength > matchStartIndex) { startLine = i; startColumn = matchStartIndex - currentIndex; break; } currentIndex += lineLength; } // Calculate line and column for end position let endLine = startLine; let endColumn = startColumn; let charsRemaining = matchText.length; while (charsRemaining > 0 && endLine < lines.length) { const lineRemainder = lines[endLine].length - endColumn + 1; // +1 for newline if (charsRemaining <= lineRemainder) { endColumn += charsRemaining; charsRemaining = 0; } else { charsRemaining -= lineRemainder; endLine++; endColumn = 0; } } // Adjust end column to be exclusive (pointing to the character after the match) if (endColumn > 0 && lines[endLine] && endColumn <= lines[endLine].length) { // No adjustment needed, end column already points to the character after the match } else { // End of line or beyond, set to 0 and increment line endColumn = 0; endLine++; } matches.push({ match: matchText, line: startLine, column: startColumn, endLine: endLine, endColumn: endColumn }); } return matches; } catch (error) { throw new Error(`Error processing regex: ${error instanceof Error ? error.message : String(error)}`); } }