StockTagParser.cs 1.6 KB

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