WPF 텍스트 편집기에서 서식 있는 하이퍼링크를 붙여넣고 서식을 지정하는 방법 > 블로그 & Tips

본문 바로가기

ComponentOne

블로그 & Tips

WPF 텍스트 편집기에서 서식 있는 하이퍼링크를 붙여넣고 서식을 지정하는 방법

페이지 정보

작성자 GrapeCity 작성일 21-09-28 16:56 조회 1,190회 댓글 0건

본문

우리가 학교에서 가장 먼저 배운 기술 중 하나는 쓰기입니다. 중요한 기술인 쓰기는 아이디어와 생각을 다른 사람에게 표현하도록 합니다. 여러분이 작성한 보고서, 밤새 작성한 영업 제안서, 고객이 필요로 하는 사용자 설명서를 떠올려 보세요. 쓰기는 업무 또는 종사하는 업종에 상관 없이 우리가 하는 일의 기본입니다. 최신 텍스트 편집기를 사용하면 "쓰기"를 할 때 도움을 받을 수 있습니다.

텍스트 편집기는 최종 사용자를 위한 지원 도구로, 원활한 쓰기 경험을 제공합니다. WPF용 C1RichTextBox는 이러한 텍스트 편집기 중 하나로, 사용자에게 단락, 목록, 표, 사진 등 다양한 입력 형식을 제공합니다. 이 포스팅에서는 이러한 입력 형식 중 하나인 하이퍼링크로 작업하는 방법에 대해 살펴볼 것입니다. C1RichTextBoxC1TextParser 라이브러리와 함께 사용하여 URL을 자동으로 하이퍼링크로 변환하고 서식을 지정하는 방법에 대해 살펴보겠습니다.

입력


하이퍼링크 추가 – 기존의 방법

C1RichTextBox에 하이퍼링크 추가는 MS Word와 같은 널리 사용되는 편집기에서 본 방법과 동일합니다. 아래 표시된 것과 비슷한 팝업 창을 열고 텍스트와 URL을 필요한 값으로 설정하여 도구 모음에서 완료할 수 있습니다.

하이퍼링크

팝업과 비슷한 이 창은 대부분의 텍스트 편집기에서 볼 수 있습니다. 이 창은 쉽고 간단하게 사용할 수 있지만 최신 텍스트 편집기에서 기대하는 원활한 경험과 거리가 있습니다. 이 팝업을 완전히 건너뛸 수 있다면 어떻게 될까요? URL을 붙여넣을 수 있고 편집기에서 해당 URL을 읽을 수 있는 하이퍼링크 텍스트로 변환한다면 어떨까요? 다음 섹션에서는 C1TextParser를 사용하여 이 작업을 수행하는 방법을 살펴보겠습니다.


URL 추출

C1TextParser는 다양한 반구조화된 소스(예: Emails/Html/PlainText 등)에서 구조화된 정보를 추출하도록 하는 강력한 텍스트 구문 분석 .NET 라이브러리입니다. 이 포스팅에서는 StartsAfter/ContinuesUntil(Ends Before) 텍스트 구 사이에 있는 모든 텍스트를 추출하는 TextParser의 Starts-After-Continues-Until 추출기를 사용합니다.

Starts-After-Continues-Until 추출기 사용은 간단합니다. 구 사이에 추출할 텍스트가 있는 시작 및 종료 정규식을 제공해야 합니다. 다음 코드 조각은 주어진 텍스트에서 URL을 추출하는 예를 보여 줍니다.

public IEnumerable<string> ExtractURLs(string text)
{
  List<string> urls = new List<string>();
  text += " "; //To adjust for urls at the end of the string
  foreach (var protocol in _protocols) // _protocols = ["http","https"]
  {
      var links = ExtractData(text, protocol, @"\s+");
      foreach (var link in links.Select(x => x.ExtractedText))
      {
          string hyperlink = $"{protocol}{link}";
          if (!Uri.IsWellFormedUriString(hyperlink, UriKind.Absolute))
              continue;
          urls.AddIfNotExist(hyperlink);
      }
  }
  return urls;
}
​
private List<ExtractedData> ExtractData(string text, string startsAfter, string continueUntil)
{
  var extractor = C1TextParserWrapper.GetStartsAfterContinuesUntilExtractor(startsAfter, continueUntil);
  var result = extractor.Extract(new MemoryStream(Encoding.UTF8.GetBytes(text)));
  var jObject = Newtonsoft.Json.Linq.JObject.Parse(result.ToJsonString());
  var jToken = jObject.GetValue("Result");
  var extractedData = jToken.ToObject<List<ExtractedData>>();
  return extractedData;
}  


C1RichTextBox에서 나중에 이 추출 로직을 사용하기 위해 아래 표시된 HyperLinkParser의 ExtractURLs 메서드로 이 로직을 모두 옮겨 두겠습니다.

public interface IHyperlinkParser
{
  IEnumerable<string> ExtractURLs(string text);
  string GetDisplayText(string uri);
}


다음 섹션에서는 지정된 URI에 대한 표시 텍스트 추출에 대해 살펴볼 것입니다.


URI에 대한 표시 텍스트 추출

위에서 추출한 각 URI는 Uri.IsWellFormedUriString을 사용하여 검증되었습니다. 이 검증은 표시 텍스트 추출에서 매우 중요한 역할을 합니다. 추출된 각 텍스트가 유효한 URI이면 URI 호스트, 세그먼트 및 쿼리 속성을 사용하여 주어진 URI를 단어로 나눌 수 있습니다. 여기서 각 단어는 다음을 나타낼 수 있습니다.

  • 도메인 이름

  • 세그먼트 경로

  • 쿼리 매개 변수 이름 및 값

예를 들어, 다음 코드는 C1TextParser를 사용하여 도메인 이름을 얻기 위해 호스트 속성을 나누는 것을 보여 줍니다.

private string ExtractDomainName(Uri uri)
{
  IEnumerable<string> data = null;
  int dotCount = uri.Host.Count(x => x == '.');
  // This condition will be executed for extracting domain name if the uri host contains more than 1 dot('.'). For example, www.google.com
  if (dotCount > 1)
      data = ExtractData(uri.Host, @"\.", @"\.").Select(x => x.ExtractedText);
​
  // This condition will be executed for extracting domain name if the uri host contains only one dot('.'). For example, youtube.com
  if (dotCount == 1)
      data = ExtractData($" {uri.Host}", @" ", @"\.").Select(x => x.ExtractedText);
  var domainName = data.Where(x => !string.IsNullOrEmpty(x.Trim())).First();
  return string.IsNullOrEmpty(domainName) ? uri.Host : domainName; }
}


마찬가지로, C1TextParser를 사용하여 URI에서 세그먼트와 쿼리 매개 변수를 추출할 수 있습니다. 이러한 추출의 구현 세부 정보를 확인하려면 블로그 맨 아래 첨부된 샘플을 참조하십시오. 그 뒤에 다음 로직을 사용하여 표시 텍스트를 선택합니다.

public string GetDisplayText(string uri)
{
  try
  {
      var words = // code to break URI into words from the Host,Segments and Query
      var displayText = ChooseDisplayText(words);
      return string.IsNullOrEmpty(displayText) ? uri : displayText;
  }
  catch
  {
      return uri;
  }
}
​
protected virtual string ChooseDisplayText(List<string> words)
{
  if (words.Count == 0)
      return null;
  var queryParams = words.Where(x => x.Contains(";"));
  var segmentsAndDomain = words.Where(x => !x.Contains(";"));
  string displayText = string.Empty;
​
  //If Query Params are present include them in the displayText
  if (queryParams.Count() > 0)
      displayText = $"({string.Join(" ", queryParams)})";
​
  //If Query Params are present also include the last segment in the display text
  if (!string.IsNullOrEmpty(displayText))
      displayText = $"{segmentsAndDomain.Last()}{displayText}";
​
  // If Query Params are not present get the display text from the segment or domain name
​
  if (string.IsNullOrEmpty(displayText))
  {
      words.Reverse();
      for (int index = 0; index < words.Count; index++)
      {
          if (double.TryParse(words[index], out double _))
              displayText = $" {words[index]}";
          else
          {
              displayText = $"{words[index]}{displayText}";
              break;
          }
      }
  }
  if (displayText.Split(_splitters, StringSplitOp-tions.RemoveEmptyEntries).Length == 1)
      return displayText.ToFirstUpper();
​
  return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(displayText);
}  


이렇게 하면 추출 로직이 완성됩니다. 지금까지 C1TextParser를 사용하여 다음 작업을 수행했습니다.

  1. 주어진 텍스트에서 URL 목록 추출

  2. 도메인, 세그먼트, 쿼리 정보를 추출하여 주어진 URI에 대한 표시 텍스트를 가져옵니다.

다음으로 가져온 텍스트를 C1RichTextBox와 통합하는 방법을 살펴볼 것입니다.


하이퍼링크 추가 – 스마트한 방법

포스팅 앞 부분에서 C1RichTextBox에 하이퍼링크를 추가하는 기존의 접근 방식을 살펴보았습니다. 위에서 정의한 HyperlinkParser를 사용하여 C1RichTextBox에서 일부 텍스트를 붙여넣고 해당 텍스트의 서식을 읽을 수 있는 하이퍼링크 텍스트로 지능적으로 지정할 때 URL을 감지하는 방법을 알아 보겠습니다. 다음은 이러한 변환을 위한 단계입니다.

  1. C1RichTextBox의 ClipboardPasting 이벤트를 구독합니다.

  2. 이벤트 처리기에서 붙여넣은 텍스트가 유효한 URI인지 아닌지 확인합니다.

  3. 유효한 URI인 경우 다음 단계를 수행합니다.

    • HyperlinkParser를 사용하여 표시 텍스트를 가져옵니다.
    • 표시 텍스트와 URI를 사용하여 HTML 앵커 태그를 만듭니다.
    • 클립보드 데이터를 앵커 태그로 바꿉니다.
  4. 붙여넣은 텍스트가 유효한 URI가 아닌 경우 다음 단계를 수행합니다.

    • HyperlinkParser를 사용하여 텍스트에서 모든 URL을 추출합니다.
    • 추출한 각 URL에 대해 표시 텍스트를 가져와 해당하는 앵커 태그를 만듭니다.
    • 텍스트의 URL을 앵커 태그로 바꿉니다.
    • 클립보드 데이터를 앵커 태그가 포함된 새 텍스트로 바꿉니다.

다음은 위 단계에 대한 코드 조각입니다.

private void OnClipboardPasting(object sender, ClipboardEventArgs e)
{
  try
  {
      string text = Clipboard.GetText();
      if (Uri.IsWellFormedUriString(text, UriKind.Absolute))
      {
          var displayText = HyperlinkParser.GetDisplayText(text);
          var anchor = $"<a href={text}>{displayText}</a>";
          Clipboard.SetData(DataFormats.Html, anchor);
      }
      else if (!string.IsNullOrEmpty(text))
      {
          var links = HyperlinkParser.ExtractURLs(text).ToList();
          foreach (var link in links)
          {
              var displayText = HyperlinkParser.GetDisplayText(link);
              var anchor = $"<a href={link}>{displayText}</a>";
              var pattern = $@"(^|\s){link}(\s|$)";
              Regex rgx = new Regex(pattern, RegexOptions.Compiled);
              text = rgx.Replace(text, $" {anchor} ");
          }
          Clipboard.SetData(DataFormats.Html, text);
      }
  }
  catch
  {
  }
}  


하이퍼링크


결론

위 문서에서는 사용자가 URL을 붙여넣을 때 하이퍼링크를 추가하기 위한 지능적인 최신 방법을 만들기 위해 C1TextParser 와 C1RichTextBox를 결합했습니다. 마찬가지로, 입력하는 중 URL을 변환할 수 있도록 C1RichTextBox TextChanged, KeyDown 이벤트를 처리할 수도 있습니다.

입력

위 구현의 전체 코드는 첨부파일을 통해 다운로드 받으실 수 있습니다.

또한, C1TextParserC1RichTextBox에 대해 자세히 읽어 보시기 바랍니다.




지금 바로 ComponentOne을 다운로드하여 직접 테스트해보세요!

c1.png

 
  • 페이스북으로 공유
  • 트위터로  공유
  • 구글플러스로 공유
  • 카카오톡으로 보내기

댓글목록

등록된 댓글이 없습니다.

그레이프시티 홈페이지를 통해 제품에 대해서 더 자세히 알아 보세요!
홈페이지 바로가기

태그

인기글

더보기
  • 인기 게시물이 없습니다.
그레이프시티 홈페이지를 통해 제품에 대해서 더 자세히 알아 보세요!
홈페이지 바로가기
이메일 : sales-kor@grapecity.com | 전화 : 1670-0583 | 경기도 안양시 동안구 시민대로 230, B-703(관양동, 아크로타워) 그레이프시티(주) 대표자 : 허경명 | 사업자등록번호 : 123-84-00981 | 통신판매업신고번호 : 2013-경기안양-00331 Copyright ⓒ 2022 GrapeCity inc.