Replace words\characters in text file

1628
10
Jump to solution
07-05-2022 04:01 AM
anTonialcaraz
Occasional Contributor II

Hi, I'm trying to replace some characters within a lyrx file.

In this example I need to replace "570" with "560"

The problem I have is that two lines are identical but I only need to replace one (highlighted in yellow in the image below) and not the one a few lines above the highlighted one.

The code I'm using:

 

for i, line in enumerate(fileinput.input(OUT_workspace + "\\" + "AE000S560_005M5001P01M041.lyrx", inplace=1)):
    sys.stdout.write(line.replace('"max" : 570', '"max" : 560'))

 

I would really appreciate any help. I'm not sure how to target a specific line within the file. Many thanks.

 

Capture.PNG

0 Kudos
2 Solutions

Accepted Solutions
anTonialcaraz
Occasional Contributor II

Thanks Brian. Does not seem to work unfortunately as the values don't change. Please see the code.

 

import arcpy
import os
import string
import sys
import fileinput
from arcpy import env
arcpy.env.overwriteOutput=True
from arcpy.sa import*





env.workspace = r"H:\PROGRAMMES\10_OTHER_PROJECTS\26_04072022_KEV"
OUT_workspace = r"H:\PROGRAMMES\10_OTHER_PROJECTS\26_04072022_KEV_NEW"

Lyrx = "AE000S570_005M5001P01M041.lyrx"

# Copy new file into new folder

arcpy.Copy_management(Lyrx, OUT_workspace + "\\" + "AE000S570_005M5001P01M041.lyrx")
arcpy.Copy_management(Lyrx, OUT_workspace + "\\" + "AE000S560_005M5001P01M041.lyrx")


with open(OUT_workspace + "\\" + "AE000S560_005M5001P01M041.lyrx") as fp:
    lyrx = fp.read()
lyrx.replace('570,\n"max"', '560,\n"max"')

 

View solution in original post

0 Kudos
Brian_Wilson
Occasional Contributor III

You need to write the changed string back out to a file, you could do this, and avoid loading all those libraries you don't need too. Loading "arcpy" takes forever.

import os

IN_workspace = r"H:\PROGRAMMES\10_OTHER_PROJECTS\26_04072022_KEV"
OUT_workspace = r"H:\PROGRAMMES\10_OTHER_PROJECTS\26_04072022_KEV_NEW"

Lyrx = "AE000S570_005M5001P01M041.lyrx"

with open(os.path.join(IN_workspace, Lyrx), "r") as fp:
    lyrx = fp.read()

fixed = lyrx.replace('570,\n"max"', '560,\n"max"')
if lyrx == fixed:
    print("WARNING, NOTHING CHANGED!")

with open(os.path.join(OUT_workspace, Lyrx), "w") as fp:
    fp.write(fixed)

 

I used "os.path.join" to build up the file paths just because it is tidier, sometimes that avoids problems with missed slashes and stuff like that. It's OS independent too. 

I avoid relying on the arcgis "workspace" because about 1/2 the Esri tools just ignore it. 

 

View solution in original post

10 Replies
RPGIS
by
Occasional Contributor III

Hi @anTonialcaraz,

I assume that you are using python. If that is the case, another option instead of using replace would be to create a dictionary so that the set values in the dictionary are overwritten to the value that you specify. 

maxvalue = {"max": 560}
for i, line in enumerate(fileinput.input(OUT_workspace + "\\" + "AE000S560_005M5001P01M041.lyrx", inplace=1)):
    #insert line exception below for specific line to update
    if i ==(line number to change):
        maxvalue["max"] = 570
        sys.stdout.write(maxvalue["max"])

Without knowing the code specifics, this is the only suggestion I can come up with at the moment.

 

0 Kudos
anTonialcaraz
Occasional Contributor II

Thanks very much @RPGIS, I appreciate.

Yes, I'm using Python. I've tried this:

maxvalue = {"max": 570}
for i, line in enumerate(fileinput.input(OUT_workspace + "\\" + "AE000S560_005M5001P01M041.lyrx", inplace=1)):
    #insert line exception below for specific line to update
    if i ==(706):
        maxvalue["max"] = "560"
        sys.stdout.write(maxvalue["max"])

 But the result I'm getting is simply "560". All the rest of the contents in the .lyrx file are gone.

Any suggestions?

0 Kudos
RPGIS
by
Occasional Contributor III

You would need to access the activeSlice dictionary(wherever that is being stored), then access the rangeDimensionValue dictionary to set the max within that dictionary. To do that, you would simply need to find where the activeSlice is the key and then access the values within that key. Then access the rangeDimensionValue values to then set the max to the specified value.

You may be able to access that particular value as such:

"activeSlice"["rangeDimensionValue"]["max"]= maxvalue["max"]

I can't tell (based on the png) if those values are in both lists and dictionaries, or a combination of sorts. If you can find the activeSlice key, then you should be able to use the suggestion above to change the max value.

0 Kudos
anTonialcaraz
Occasional Contributor II

Thanks again @RPGIS.

I'm not very familiar with the activeSlice dictionary concept unfortunately. Must admit I'm a bit lost now.

Please let me pass you the .lyrx file see if that makes things easier. I just need to replace the rangeDimensionValue of several files. For example, from 570 to 560. I was initially using line.replace but that would change the "customFullExtent" part as well and I need that to keep the same values.

0 Kudos
RPGIS
by
Occasional Contributor III

The activeSlice is a specific key storing all other values that are assigned to that key.

Python Dictionaries (w3schools.com)

0 Kudos
TomGeo
by
Occasional Contributor III

Hi, why don’t you parse the lyrx and then you can address the “rangeDimensionValue” directly?

- We are living in the 21st century.
GIS moved on and nobody needs a format consisting out of at least three files! No, nobody needs shapefiles, not even for the sake of an exchange format. Folks, use GeoPackage to exchange data with other GIS!
0 Kudos
by Anonymous User
Not applicable

Couple things here- fileinput will basically create an list of lines from the text file so I don't think you can access the 'keys' as structured in the png or python dictionary. Enumerate creates an inplace tuple containing the index number and value (line).

Meaning line 706 will just look like '"max": 570' when you are iterating over it. To replace it, use '"max": 560'. Also, if you don't put anything back to the file if it doesn't match in the if, fileinput erases it which is probably why you only ended up with 560.

 

for i, line in enumerate(fileinput.input(OUT_workspace + "\\" + "AE000S560_005M5001P01M041.lyrx", inplace=1)):
    #insert line exception below for specific line to update
    if i == 760:
        sys.stdout.write("max": 560) # or '"max": 560', im not sure which would work
    else:
        sys.stdout.write(line)

 

 

0 Kudos
Brian_Wilson
Occasional Contributor III

Treat the entire file as one string with newlines embedded in it, then use "replace".

 

lyrx is the string containing the entire file

Line 3 looks for the pattern of 560 on a line and "max" on the next line then replaces that with the new value

with open("file.lyrx") as fp: 
  lyrx = fp.read()
lyrx.replace('560,\n"max"', '570,\n"max"'))

 

If you want a more general approach that deals with random whitespace you could use the re.sub instead, you can go down a real rabbit hole with regex though so use plain old replace unless you are getting fancy.

import re
fixed = re.sub('560,\s*"max"','570,\n"max"',lyrx)

 

0 Kudos
anTonialcaraz
Occasional Contributor II

Thanks Brian. Does not seem to work unfortunately as the values don't change. Please see the code.

 

import arcpy
import os
import string
import sys
import fileinput
from arcpy import env
arcpy.env.overwriteOutput=True
from arcpy.sa import*





env.workspace = r"H:\PROGRAMMES\10_OTHER_PROJECTS\26_04072022_KEV"
OUT_workspace = r"H:\PROGRAMMES\10_OTHER_PROJECTS\26_04072022_KEV_NEW"

Lyrx = "AE000S570_005M5001P01M041.lyrx"

# Copy new file into new folder

arcpy.Copy_management(Lyrx, OUT_workspace + "\\" + "AE000S570_005M5001P01M041.lyrx")
arcpy.Copy_management(Lyrx, OUT_workspace + "\\" + "AE000S560_005M5001P01M041.lyrx")


with open(OUT_workspace + "\\" + "AE000S560_005M5001P01M041.lyrx") as fp:
    lyrx = fp.read()
lyrx.replace('570,\n"max"', '560,\n"max"')

 

0 Kudos