이슈
DB에 저장되어있는 게시판 내용 중 img 태그 안에 있는 width, height 속성을 삭제하거나 변경해야 할 일이생겼다.
목표
- inline width, height 속성은 삭제
- style 안의 width, height 값은 100% 로 변경
1 2 3 4 5 6 7
| <img src="..." width="200" height="300"> <img alt="..." style="width:200px; height:500px;">
<img src="..."> <img alt="..." style="width:100%; height:100%;">
|
분석
게시글이 천개가 넘게 등록되어있어서 내용을 하나하나 고치는 것은 매우 비효율적이다.
그래서 DB에서 데이터를 불러와 자바 정규식을 이용해 치환하여 UPDATE 하는 방법을 선택했다.
우선 변경할 테이블을 백업해준다.
1
| create table board_bak as select * from board
|
업데이트 소스는 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| public class ImgWidthHeightReplacer { private Connection connection = null; private PreparedStatement selectPs = null; private PreparedStatement updatePs = null; private static final String UPDATE_EMPTY = "UPDATE board SET contents = empty_clob() WHERE board_seq = ?"; private static final String SELECT_LOCK = "SELECT contents FROM board WHERE board_seq = ? for update"; public void replaceContents() throws SQLException, IOException { String sql = "select board_seq, contents from board where use_html = 'Y'"; getConnection(); selectPs = connection.prepareStatement(sql); ResultSet rs = selectPs.executeQuery(); while(rs.next()) { String contents = rs.getString("contents"); if(contents != null) { String reContents = contents.replaceAll("(<img[^>]*)(width=[\"]?[^>\"]+[\"]?)([^>]*>)", "$1$3") .replaceAll("(<img[^>]*)(height=[\"]?[^>\"]+[\"]?)([^>]*>)", "$1$3") .replaceAll("(<img[^>]*style=\"[^>]*width:)([a-zA-Z0-9]*;?)([^>]*\")", "$1100%;$3") .replaceAll("(<img[^>]*style=\"[^>]*height:)([a-zA-Z0-9]*;?)([^>]*\")", "$1100%;$3"); updateContents(reContents, rs.getInt("board_seq")); } } closeResultSet(rs); closeSelectPs(); closeConneciton(); } private void updateContents(String contents, int boardSeq) throws IOException { ResultSet rs = null; try { connection.setAutoCommit(false); updatePs = connection.prepareStatement(UPDATE_EMPTY); updatePs.setInt(1, boardSeq); if(updatePs.executeUpdate() > 0) { closeUpdatePs(); updatePs = connection.prepareStatement(SELECT_LOCK); updatePs.setInt(1, boardSeq); rs = updatePs.executeQuery(); while(rs.next()) { CLOB cl = ((OracleResultSet)rs).getCLOB("contents"); BufferedWriter writer = new BufferedWriter(cl.getCharacterOutputStream()); writer.write(contents); writer.close(); } connection.commit(); } } catch (SQLException e) { e.printStackTrace(); try { connection.rollback(); } catch (SQLException e1) { System.out.println("rollback fail"); } } finally { try { connection.setAutoCommit(true); } catch (SQLException e) {} closeResultSet(rs); closeUpdatePs(); } }
private void getConnection() { try { if(connection == null || connection.isClosed()) { Class.forName("oracle.jdbc.OracleDriver"); connection = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:ORA9", "user", "password"); } } catch (Exception e) { System.out.println("connection fail"); } } private void closeConneciton() { if(connection != null) { try { connection.close(); } catch (Exception e) { e.printStackTrace(); } } }
private void closeUpdatePs() { if(updatePs != null) { try { updatePs.close(); } catch (Exception e) { e.printStackTrace(); } } }
private void closeSelectPs() { if(selectPs != null) { try { selectPs.close(); } catch (Exception e) { e.printStackTrace(); } } }
private void closeResultSet(ResultSet rs) { if(rs != null) { try { rs.close(); } catch (Exception e) { e.printStackTrace(); } } }
public static void main(String[] args) throws Exception { ImgWidthHeightReplacer instance = new ImgWidthHeightReplacer(); instance.replaceContents(); } }
|
중요한 부분은 replaceContents() 메서드의 정규식 부분이다.
치환 정규식
- (<img[^>])(width=["]?[^>"]+["]?)([^>]>)
- 1번 그룹 (<img[^>]*)
- <img 문자열 뒤에 > 가 아닌 문자가 0개 이상
- 2번 그룹 (width=["]?[^>"]+["]?)
- width= 문자열 뒤에 “ 문자가 0 이나 1개
- 문자 > 와 “ 가 아닌 문자가 하나 이상
- “ 가 있거나 없음
- 3번 그룹 ([^>]*>)
그룹캡쳐를 사용해 치환자를 $1$3으로하여 2번 그룹을 삭제한다. 결국 img 태그의 width=”…” 부분이 삭제된다.
- (<img[^>]*style="[^>]width:)([a-zA-Z0-9];?)([^>]*")
- 1번 그룹 (<img[^>]*style="[^>]*width:)
- img 태그 안에 style=”… width: 까지 캡쳐
- 2번 그룹 ([a-zA-Z0-9]*;?)
- 3번 그룹 ([^>]*")
실행결과 제대로 변경된 것을 확인할 수 있었다.
실무에서 이런 류의 작업을 해야하는 경우가 종종 있는데 정규식을 적절하게 사용하면 쉽게 수정이 가능하다.
끝으로 리눅스에서 파일의 특정 문자를 치환하는 방법을 소개하면서 마친다.
리눅스 파일 문자열 치환
1
| find ./ -name "*.jsp" |xargs sed -i "s/jquery-3.2.1.min.js/jquery-3.3.1.min.js/g"
|
현재폴더 아래의 jsp 파일 모두를 검색하여 “jquery-3.2.1.min.js” 문자열을 “jquery-3.3.1.min.js” 로 치환