NOMO.asia

어떤 글에서 특정 키워드들을 찾아 자동으로 링크를 달아주려고 방법을 고민해보았다.

고민해야 하는 것들

처음에는 쉽게 구현할 수 있을거라고 생각했지만 구현하다보니 몇가지 걸리는 부분이 있었다.

  1. 키워드에 이미 링크가 걸려있다면 링크를 달아서는 안 된다.
    그냥 링크를 달아버리면 링크가 중첩해서 걸릴 수 있다.
  2. html 태그는 바꾸면 안 되고, text 만 바꿔주어야 한다.
    예를 들어, 이미지 src 속성, 그러니까 이미지 주소에 키워드가 포함되어 있다고 해서 이미지 주소의 일부를 <a> 태그로 감싸버리면 이미지가 깨져서 출력될 것이다.
  3. 이미 찾아서 링크를 단 것에 다시 링크를 달아서는 안 된다.

안 좋은 예시

예를 들어, 아래와 같은 글이 있다고 하자.


pineapple은 맛있어.


pineapple 과 apple 이라는 키워드가 있을 때, pineapple 이라는 키워드에 링크를 먼저 걸면 아래와 같이 된다.


<a href="http://pineapple.com">pineapple</a>은 맛있어.

이후 링크를 건 대상에 대한 필터링 없이 그냥 바로 apple 이라는 키워드에 링크를 걸면 아래와 같이 될 수도 있다.


<a href="http://pine<a href="apple.com">apple</a>.com">pine<a href="apple.com">apple</a>은 맛있어.


구현 시 위와 같은 문제를 주의해야 했다.

알고리즘

구현하기 위한 방법을 고민하다가 가장 먼저 떠올린 방법은, 검색할 대상의 html 을 그냥 일종의 text(string) 으로 보고, <a와 >로 감싸진 부분과 그렇지 않은 부분을 나눠, 순차적으로 배열에 저장한 뒤 <a와 >로 감싸지지 않은 부분에 대해서만 처리한 후 마지막에 다시 join 해주는 방법이었다. 하지만 방법이 아름답지 않았고, 많은 예외가 발생할 수 있어서 에러처리를 해줘야 할 부분이 많다고 생각되었다.


이러한 문제를 해결하기 위한 방법을 찾다가 NodeType 으로 element 를 걸러주면 된다는 것을 알았다.

순서는 아래와 같다.

  1. 키워드-링크 객체를 배열에 저장한다.
  2. 키워드를 검색할 대상이 포함된 element 를 고른다.
  3. 해당 element 및 해당 엘리먼트의 모든 Node를 검색한다.
  4. NodeType === 3 인 element 만을 필터링한다.
    NodeType === 3 은 text node 를 의미한다. (참고 링크 https://developer.mozilla.org/ko/docs/Web/API/Node/nodeType#Node_type_constants)
  5. 필터링 된 element 중, 태그가 a 가 아닌 element 만을 필터링한다.
  6. 필터링 된 element 들에 대하여 키워드 하나를 검색한 뒤 일치하는 키워드가 있는 경우 a 태그로 감싼 뒤 지정된 링크를 건다.
  7. 키워드가 포함된 element의 경우, 키워드를 하나 찾아 링크를 건 뒤에
    해당 element 에 대하여 모든 Node 를 다시 찾아 NodeType 을 다시 체크하여
    a 태그를 제외한 element 를 고르도록 다시 필터링한다.
    왜냐하면 해당 element 에 다른 키워드가 여러개 있을 수 있기 때문이다.

더 쉬운 방법이 있을 것 같지만, 일단 여기서 마무리했다.

코드 및 예제

아래는 작성한 코드와 테스트 예제이다. jQuery를 이용하였다. 예제 링크는 https://jsfiddle.net/nomomo/hcadj639/
여러 키워드가 동일한 링크를 가리킬 수 있도록 하나의 링크에 대한 키워드를 배열로 저장했다.
[자동 링크 변환(클릭)] 을 누르면 키워드에 링크가 생성된다.

결과적으로 삼중 반복문이 되었다. 일단 만들어놓고 문제가 없어서 그냥 쓰고는 있지만, 계산을 줄일만한 여지가 많이 있을 것 같기는 하다.
어떤 엘리먼트에 대하여 하나의 키워드가 검색된 경우, 재귀호출을 통해 그 엘리먼트에 대해서만 함수를 재귀적으로 다시 실행하고, 기존에 돌던 함수에서는 다음번 엘리먼트에서 검색을 계속하도록 하는 방법으로 검색을 줄이긴 했다. 재귀호출 시 어떤 키워드까지 검색했는지까지 넘겨주면 계산을 더 줄일 수 있을 것같다.
최종적으로 태그 중 일부분이 <autokeyword>로 감싸지게 되는데 이게 마음이 들지 않는다면 후처리로 없애주면 된다.