简体   繁体   中英

To extract specific string from txt file and copy the extracted string to json file in batch file

I have text file abc.txt with the contents as :

abc.txt :

{"nature":"calm","trees":"uprooted from the main area","name":"usdbuebcowecy821nkwh29y2bnso3ns389ye3wnsiwsn9usj","enrolled":"not yet"}

I need to extract the string "usdbuebcowecy821nkwh29y2bnso3ns389ye3wnsiwsn9usj" associated with name from the abc.txt. The strings associated with name vary and are not static. Hence whatever the string is asociated with name has to be extracted and updated in a sample.json file .

Sample.json :

 {
   "requisite":{
            "name": "usdbuebcowecy821nkwh29y2bnso3ns389ye3wnsiwsn9usj"
               },
             "land": {
                    "key": "890"
                   }
}

Sample.json file name key should be updated with the appropriate name extracted from abc.txt name field.

I tried below code snippet to extract the name field abc.txt file :

For /f "tokens=1 delims=:" %%j in ('dir /b /s "C:\abc.txt" ^|findstr /I ""name":"') do echo "%%j" 
echo name is: %%j

However the loop doesnt search for the name string and Im stuck to proceed further. Im new to batch script. Can anyone help me out?

@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q64985945.txt"
:: Read sourcefile to LINE
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO SET "line=%%a"
:: Change each { } and : to comma
SET "line=%line:{=,%"
SET "line=%line:}=,%"
SET "line=%line::=,%"
:: ensure NAME is not defined
SET "name="
:: process LINE
:: set NAME when the string `name` is detected, use that flag to set NAME to the value following.
:: Note that LINE will not contain {:}, so any of these values can be used as a flag to detect
:: `name` as the last value.
FOR %%a IN (%line%) DO IF DEFINED name (SET "name=%%~a"&GOTO done ) ELSE IF /i "%%~a"=="name" SET "name=:"
:noname
ECHO No name value found
GOTO :eof
:done
SET name

GOTO :EOF

You would need to change the setting of sourcedir to suit your circumstances. The listing uses a setting that suits my system.

I used a file named q64985945.txt containing your data for my testing.

The usebackq option is only required because I chose to add quotes around the source filename.

Unfortunately, you still keep the JSON text a er, mystery. The sample you've posted doesn't tell us a number of things - whether the first occurrence of name is the one you require, or whether there are other conditions that determine which particular value of name is to be selected. For instance, your original sample did not include nested brace-pairs. All significant in devising a solution...

The dir command show file names . You want not to process the file name, but the file contents , isn't it? So you should give "abc.txt" as parameter of findstr command.

In the line you want the sixth token separated by colon or comma , right?

This works:

For /f "tokens=6 delims=:," %%j in ('findstr /I "name" abc.txt') do echo %%j

However, if the contents of file abc.txt is just one line (as you said in the question), then you don't even need the findstr command...

For /f "tokens=6 delims=:," %%j in (abc.txt) do echo %%j

This is another way to do it that extracts the values of all variables in the line:

@echo off
setlocal

rem Read a line from abc.txt
set /P "line=" < abc.txt
rem For example: {"nature":"calm","trees":"uprooted","name":"usd","enrolled":"not yet"}

rem Remove braces  ->  "nature":"calm","trees":"uprooted","name":"usd","enrolled":"not yet"
set "line=%line:~1,-1%"

rem Change ":" by =  ->  "nature=calm","trees=uprooted","name=usd","enrolled=not yet"
set "line=%line:":"==%"

rem Change "," by " & set "  ->  "nature=calm" & set "trees=uprooted" & set "name=usd" & set "enrolled=not yet"
rem and *execute* such a line inserting a SET command at beginning:
set %line:","=" & set "%

rem Now all variables have their values. For example:
echo {"name":"%name%"}

New solution added

Your first request was to extract name field from abc.txt file. However, you have now changed the problem to update a line of sample.json file that in the original question have just one line.

Anyway, here it is a solution to your new problem:

@echo off
setlocal EnableDelayedExpansion

rem Get the value of "name": field in abc.txt file
for /f "tokens=6 delims=:," %%j in (abc.txt) do set "name=%%~j"

rem Get line number of "name": line minus one in sample.json file
for /F "delims=:" %%n in ('findstr /N "\"name\":" sample.json') do set /A "lines=%%n-1"

rem Process sample.json file and create sample.out
< sample.json (

   rem Copy first N lines
   for /L %%i in (1,1,%lines%) do set /P "line=" & echo !line!

   rem Read and update the "name": line as requested
   set /P "line="
   for /F "delims=:" %%a in ("!line!") do echo %%a: "%name%"

   rem Copy the rest of lines
   findstr "^"

) > sample.out

move /Y sample.out sample.json

Note that this code is prone to get errors because Batch files are not designed to process json files. If the program fails with your real data because a detail that is different from the posted data, please do not post here a request to fix the code! :(

/ has no support for JSON at all, so please use a tool like that does.

dot notation:

xidel -s sample.json -e "($json).requisite.name:=json-doc('abc.txt').name"

XQuery:

xidel -s sample.json -e "$json/map:put(.,'requisite',{'name':json-doc('abc.txt')/name})"

Output (to stdout) in both cases:

{
  "requisite": {
    "name": "usdbuebcowecy821nkwh29y2bnso3ns389ye3wnsiwsn9usj"
  },
  "land": {
    "key": "890"
  }
}

To update the input file simply use --in-place :

xidel -s --in-place sample.json -e "[...]"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM