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 107 108 109 110 | package Torello.Java; import Torello.Java.Verbosity; import Torello.Java.IOExceptionHandler; import Torello.Java.FileNode; import Torello.Java.FileRW; import Torello.Java.StrIndexOf; import Torello.Java.Q; import Torello.Java.Additional.AppendableSafe; import Torello.Java.Additional.BiAppendable; import java.util.List; import java.util.function.Consumer; import java.util.stream.Stream; import java.util.stream.Collectors; import java.io.IOException; class MultiLineStrMatch { // Re-Use the Pointer, I guess private static final String I4 = Helper.I4; static void CHECK_STRS(final String matchStr, final String replaceStr) { if (matchStr.equals(replaceStr)) throw new IllegalArgumentException( "The String passed to parameter 'matcheStr' is identical to the String passed to " + "parameter 'replaceStr'. There is nothing for SED to do." ); } // Only Method static InternalSED.ResultsSED handleOneFile( final String fileName, final FileNode file, final String fileAsStr, final CONFIG_RECORD userConfig ) throws IOException { // Retrieve the starting String-index of each and every match in the file final int[] posArr = StrIndexOf.all(fileAsStr, userConfig.matchStr); if (posArr.length == 0) return InternalSED.NO_CHANGES_RET; // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // For-Loop: Print the Matches to System.out // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // "Printing Stream" saves PrintingRecMultiLine instances. final Stream.Builder<PrintingRecMultiLine> PRMLB = Stream.builder(); // Loop-Variable for retaining the previous PrintingRecMultiLine. It has the File // Line-Number information for the previous match. The Previous-Line Number info is how // Line-Number's are computed much more efficiently. PrintingRecMultiLine prevSaverRecord = null; for (int i=0; i < posArr.length; i++) { // Loop-Variable that represents the current match, indexing the 'posArr' Array final int pos = posArr[i]; // Overlapping matches need to be skipped if ((i > 0) && (pos < (posArr[i-1] + userConfig.MATCH_STR_LEN))) continue; else PRMLB.accept( prevSaverRecord = new PrintingRecMultiLine( fileAsStr, pos, // match Starting-Position pos + userConfig.MATCH_STR_LEN, // match Ending-{osition userConfig.replaceStr, // NOTE: The "value" assigned to this reference is **NOT-UPDATED** until // after it has been passed to this method's parameter. prevSaverRecord, userConfig.useUNIXColors )); } // All Printing-Records as an Array final PrintingRecMultiLine[] prmlArr = PRMLB.build().toArray(PrintingRecMultiLine[]::new); if (prmlArr.length == 0) return InternalSED.NO_CHANGES_RET; // unless Verbosity.Silent was requested, print the matches. if (userConfig.verbosity.level > 0) PrintingRecMultiLine.printAll (prmlArr, userConfig.appendable, userConfig.useUNIXColors, userConfig.verbosity); // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Query the User, Write the Replacement // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** if (userConfig.askFirst) if (! Q.YN("Re-Write the Updated File to Disk?")) return InternalSED.NO_CHANGES_RET; // Remember, this single line of code does the actual replacement! String newFileAsStr = fileAsStr.replace(userConfig.matchStr, userConfig.replaceStr); return new InternalSED.ResultsSED(newFileAsStr, prmlArr.length); } } |