using System.Text.RegularExpressions; namespace Application.Helpers; /// /// 글 본문의 $종목 태그 파서 (d2 §③·§⑤) — 저장 토큰은 항상 코드 기준(`$005930(삼성전자)`)이므로 /// `$` 뒤 6자리 숫자만 추출한다(뒤의 `(종목명)` 은 표시용, 파싱 무시). 종목명 동명(우선주 등) 모호성 회피. /// /// 규칙: /// • `$` + 정확히 6자리 숫자 → 코드로 채택 (예: `$005930`, `$005930(삼성전자)`). /// • 6자리 뒤에 숫자가 더 붙으면(예: `$0059301`) 종목코드로 보지 않는다(경계 검사). /// • 중복 코드는 1건으로 dedupe, 등장 순서를 유지한다. /// 순수 함수 — DB 접근 없음(존재 검증은 호출자가 AnyAsync 로 수행). /// public static class StockTagParser { // $ 다음 6자리 숫자, 뒤에 숫자가 이어지지 않을 때만(경계). 앞의 $ 는 캡처 대상 아님. private static readonly Regex TagPattern = new(@"\$(\d{6})(?!\d)", RegexOptions.Compiled | RegexOptions.CultureInvariant); /// 본문에서 $종목 코드들을 등장 순서대로 중복 제거해 추출한다. 없으면 빈 목록. public static List Extract(string? content) { if (string.IsNullOrEmpty(content)) { return []; } var seen = new HashSet(); var result = new List(); foreach (Match match in TagPattern.Matches(content)) { var code = match.Groups[1].Value; if (seen.Add(code)) { result.Add(code); } } return result; } }