Search code examples
batch-filejrepl

How to replace only the first match in a text file with jrepl using /pflag "i" switch?


I am trying to replace only the first match in a text file.

My code is:

FOR /R %%a IN ("*.out") DO call C:\qsi\jrepl.bat "FF**********" "**********" /f "%%a" /L /m /o -

The FF before the asterisks is representing a form feed character.
The code is for removing the form feed for the first match only.

I was trying to play with /p & /pflag "i", but could not get it to work.

I am using the latest version 8.2 of JREPL.BAT.


Solution

  • It is possible to use the JREPL.BAT option /INC if the first form feed is within a specific block at top of a text file and there is never one more form feed in same block.

    Example for first form feed within the lines 3 to 10:

    @echo off
    for /R %%I in ("*.out") do call C:\qsi\jrepl.bat "\f" "" /INC "3:10" /F "%%I" /O -
    

    The JScript regular expression search string \f matches a form feed control character.
    The replace string is an empty string to remove the form feed in this include block.

    The option /L for a literal search cannot be used on using \f or alternatively \x0C (hexadecimal value of form feed control character) in search string.

    The option /M cannot be used on using option /INC as explained by help output on running JREPL.BAT in a command prompt window with /? or /??. The lines respectively the line endings must be detected and counted to identify the block from line 3 to line 10 on which the replace should be done and nothing outside this block.

    A solution using option /PFLAG is also possible by using:

    for /R %%I in ("*.out") do call C:\qsi\jrepl.bat "\f" "" /M /P "\f" /PFLAG "" /F "%%I" /O -
    

    JREPL.BAT runs a JScript regular expression replace with these options searching for a form feed character in entire file because of option /M. It replaces only first form feed because of using the option /PFLAG "" which means running the case-sensitive replace without flag g for a non-global replace.

    But it is necessary to specify also option /P with a regular expression string in addition to the regular expression search string specified as first argument for usage of option /PFLAG with empty flag string "" or with "i" for a non-global case-insensitive search. In this case the additional regular expression after /P is the same as the main search expression, just \f to match a form feed, the first form feed in entire file.


    UPDATE:

    The real task is to remove in a binary file first and only occurrence of the byte sequence 1B 45 and first occurrence of 0C being always after 1B 45 with keeping all other 0C in file. The binary file contains for example beginning at byte offset 752 (hexadecimal 02F0) the bytes:

    02F0h: F8 00 FC 01 F8 00 0D 0A 0D 1B 45 1B 28 73 30 70 ; ø.ü.ø.....E.(s0p
    0300h: 30 73 33 62 31 32 68 34 31 30 31 54 1B 26 6C 32 ; 0s3b12h4101T.&l2
    0310h: 61 30 6F 30 65 30 6C 38 64 38 38 46 0D 0A 1B 2A ; a0o0e0l8d88F...*
    0320h: 70 30 78 30 59 1B 2A 63 35 37 36 30 78 37 39 32 ; p0x0Y.*c5760x792
    0330h: 30 59 1B 2A 63 30 54 1B 25 31 42 53 50 31 3B 53 ; 0Y.*c0T.%1BSP1;S
    0340h: 43 30 2C 33 2E 33 38 36 37 2C 30 2C 2D 33 2E 33 ; C0,3.3867,0,-3.3
    0350h: 38 36 37 2C 32 3B 49 52 30 2C 31 30 30 2C 30 2C ; 867,2;IR0,100,0,
    0360h: 31 30 30 3B 53 50 31 3B 44 54 5E 2C 31 3B 53 44 ; 100;SP1;DT^,1;SD
    0370h: 32 2C 31 2C 34 2C 31 30 2C 35 2C 30 2C 36 2C 33 ; 2,1,4,10,5,0,6,3
    0380h: 2C 37 2C 34 31 34 38 3B 1B 25 31 41 0D 0A 0D 0A ; ,7,4148;.%1A....
    0390h: 0C 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; .***************
    03A0h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; ****************
    03B0h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; ****************
    03C0h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; ****************
    03D0h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 0D 0A 0D ; *************...
    03E0h: 0A 62 6C 61 68 20 62 6C 61 68 20 62 6C 61 68 0D ; .blah blah blah.
    03F0h: 0A 0D 0A 0C 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; ....************

    This block should be modified to:

    02F0h: F8 00 FC 01 F8 00 0D 0A 0D 1B 28 73 30 70 30 73 ; ø.ü.ø.....(s0p0s
    0300h: 33 62 31 32 68 34 31 30 31 54 1B 26 6C 32 61 30 ; 3b12h4101T.&l2a0
    0310h: 6F 30 65 30 6C 38 64 38 38 46 0D 0A 1B 2A 70 30 ; o0e0l8d88F...*p0
    0320h: 78 30 59 1B 2A 63 35 37 36 30 78 37 39 32 30 59 ; x0Y.*c5760x7920Y
    0330h: 1B 2A 63 30 54 1B 25 31 42 53 50 31 3B 53 43 30 ; .*c0T.%1BSP1;SC0
    0340h: 2C 33 2E 33 38 36 37 2C 30 2C 2D 33 2E 33 38 36 ; ,3.3867,0,-3.386
    0350h: 37 2C 32 3B 49 52 30 2C 31 30 30 2C 30 2C 31 30 ; 7,2;IR0,100,0,10
    0360h: 30 3B 53 50 31 3B 44 54 5E 2C 31 3B 53 44 32 2C ; 0;SP1;DT^,1;SD2,
    0370h: 31 2C 34 2C 31 30 2C 35 2C 30 2C 36 2C 33 2C 37 ; 1,4,10,5,0,6,3,7
    0380h: 2C 34 31 34 38 3B 1B 25 31 41 0D 0A 0D 0A 2A 2A ; ,4148;.%1A....**
    0390h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; ****************
    03A0h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; ****************
    03B0h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; ****************
    03C0h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; ****************
    03D0h: 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 0D 0A 0D 0A 62 6C ; **********....bl
    03E0h: 61 68 20 62 6C 61 68 20 62 6C 61 68 0D 0A 0D 0A ; ah blah blah....
    03F0h: 0C 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A 2A ; .***************

    So the task is to remove the two bytes 1B 45 at byte offset 761 (hexadecimal 02F9) and the byte 0C at byte offset 912 (hexadecimal 0390) without removing any other byte 0C like the one at byte offset 1011 (hexadecimal 03F3).

    The following command line can be used in a batch file for removing in such binary files containing ESC+E stored hexadecimal with the bytes 1B 45 and first Form Feed stored hexadecimal with the byte 0C:

    for /R %%I in ("*.out") do call C:\qsi\jrepl.bat "\x1BE([\s\S]+?)\f" "$1" /M /F "%%I" /O -
    

    The regular expression search string results in searching for

    • \x1BE ... a byte with hexadecimal value 1B followed by character E (case-sensitive) and
    • (...) ... with using a marking group
    • [\s\S] ... for a whitespace or a non-whitespace character, i.e. any character (or byte)
    • + ... one or more times
    • ? ... non-greedy
    • \f ... and a form feed.

    The bytes between 1B 45 and 0C matched by the expression inside marking group are back-referenced in replace string with $1 to be kept in the binary files.