/* * [SRItem.java] * * Summary: Search/Replace Script Items. * * Copyright: (c) 2011-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2011-11-13 initial version */ package com.mindprod.sortsrs; import com.mindprod.fastcat.FastCat; /** * Search/Replace Script Items. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2011-11-13 initial version * @since 2011-11-13 */ class SRItem extends Item { /** * search options without lead /, null if none * e.g.xw iw ix ih it * interned for fast == compare */ final String options; /** * bare replace string */ final String replaceUntrimmed; /** * bare search data string */ final String searchUntrimmed; /** * optional comment on replace string after [Replace], possibly null */ private final String replaceComment; /** * optional comment on search string after [Search], possibly null */ private final String searchComment; /** * Constructor * * @param searchUntrimmed search string, with trail \n\r, line after [Search xxx] line (untrimmed!) * @param searchComment comment after [Search] or null, without lead / might contain embedded / * Text editors may trim. Best to code as regex with \0x20 * @param options chars after [Search /xxxx] * @param replaceUntrimmed chars after [Replace] line (untrimmed) * Text editors may trim. Best to code as regex with \0x20 * @param replaceComment comment after [Replace] or null, without lead / might contain embedded / */ private SRItem( final String searchUntrimmed, final String searchComment, final String options, final String replaceUntrimmed, final String replaceComment ) { this.section = 1; this.searchUntrimmed = searchUntrimmed; this.searchComment = canonise( searchComment ); // leave case as is // cannot intern null this.options = ( options == null ) ? null : canonise( options ).intern(); this.replaceUntrimmed = replaceUntrimmed; this.replaceComment = canonise( replaceComment ); } /** * displays where in raw script had trouble * * @param searchMarker [Search /x /i] comment / * @param search search string, with trail \n\r, line after [Search xxx] line * @param replaceMarker [Replace] comment / * @param replace chars after [Replace] line * * @return combined string for error message. */ private static String where( final String searchMarker, final String search, final String replaceMarker, final String replace ) { final FastCat sb = new FastCat( 8 ); sb.append( " |" ); sb.append( searchMarker ); sb.append( " | " ); sb.append( search ); sb.append( " | " ); sb.append( replaceMarker ); sb.append( " { " ); sb.append( replace ); return sb.toString(); } /** * create new SRItem from raw four lines in the script * * @param searchMarker0 [Search /x /i] comment / * @param searchUntrimmed1 search string, with trail \n\r, line after [Search xxx] line * Text editors may trim. Best to code as regex with \0x20 * @param replaceMarker2 [Replace] comment / * @param replaceUntrimmed3 chars after [Replace] line * Text editors may trim. Best to code as regex with \0x20 * * @return SRItem build of fields parsed from four lines. */ public static SRItem create( final String searchMarker0, final String searchUntrimmed1, final String replaceMarker2, final String replaceUntrimmed3 ) { assert searchMarker0.startsWith( "[Search" ) : "improper searchMarker"; int optionsStartAt = searchMarker0.indexOf( '/' ); final String options; if ( optionsStartAt < 0 ) { options = null; } else { optionsStartAt++; // bypass / int optionsEndAt = searchMarker0.indexOf( ']', optionsStartAt + 1 ); if ( optionsEndAt < 0 ) { throw new IllegalArgumentException( "Error [14]: Script corrupt. Search options malformed " + where( searchMarker0, searchUntrimmed1, replaceMarker2, replaceUntrimmed3 ) ); } else { options = searchMarker0.substring( optionsStartAt, optionsEndAt ); } } final String searchComment; // comment might contain stray ] int searchCommentStartAt = searchMarker0.indexOf( ']' ); if ( searchCommentStartAt < 0 ) { throw new IllegalArgumentException( "Error [15]: Script corrupt. Search options malformed " + where( searchMarker0, searchUntrimmed1, replaceMarker2, replaceUntrimmed3 ) ); } else { searchComment = searchMarker0.substring( searchCommentStartAt + 1 ); } final String replaceComment; // comment might contain stray ] int replaceCommentStartAt = replaceMarker2.indexOf( ']' ); if ( replaceCommentStartAt < 0 ) { throw new IllegalArgumentException( "Error [16]: Script corrupt. Search options malformed " + where( searchMarker0, searchUntrimmed1, replaceMarker2, replaceUntrimmed3 ) ); } else { replaceComment = replaceMarker2.substring( replaceCommentStartAt + 1 ); } if ( !replaceMarker2.startsWith( "[Replace]" ) ) { throw new IllegalArgumentException( "Error [17]: Script corrupt. [Search]/[Replace] not interleaved properly. " + where( searchMarker0, searchUntrimmed1, replaceMarker2, replaceUntrimmed3 ) ); } return new SRItem( searchUntrimmed1, searchComment, options, replaceUntrimmed3, replaceComment ); } /** * compose a 4-line search/replace item, with lead \r \n but no trailing \r\n( * * @param stripComments true if should strip out comments * * @return chars as they appear is reconstructed script, starting with \r\n, but not not ending with it. */ public String combine( final boolean stripComments ) { final FastCat sb = new FastCat( 11 ); sb.append( "\r\n[Search" ); if ( options != null ) { sb.append( " /" ); sb.append( options ); } sb.append( "]" ); if ( !stripComments ) { sb.append( searchComment ); } sb.append( "\r\n" ); sb.append( searchUntrimmed ); sb.append( "\r\n[Replace]" ); if ( !stripComments ) { sb.append( replaceComment ); } sb.append( "\r\n" ); sb.append( replaceUntrimmed ); // no final \r\n return sb.toString(); } /** * is this a case-sensitive search? * * @return true if case-sensitive, lacking i in options */ public boolean isCaseSensitive() { return options == null ? true : !options.contains( "i" ); } /** * show all three fields, for debugging, but not the comments * * @return search/options/replace */ public String toString() { // FastCat will deal with null, leave out comments. final FastCat sb = new FastCat( 9 ); sb.append( "-SR- s{" ); sb.append( searchUntrimmed ); sb.append( "} o{" ); sb.append( options ); sb.append( "} r{" ); sb.append( replaceUntrimmed ); sb.append( "} sensitive{" ); sb.append( isCaseSensitive() ); sb.append( "}" ); return sb.toString(); } }