From eb310ffcdc1888f6b1ae83f8b1d38bc05d728941 Mon Sep 17 00:00:00 2001 From: Benjamin Dabelow <2276720+bdabelow@users.noreply.github.com> Date: Thu, 30 Mar 2023 22:10:22 +0200 Subject: [PATCH 1/4] Replace in link text and link target Replacements are being made in text and target of hyperlinks, including in header and footer. --- src/python_docx_replace/__init__.py | 18 ++++++++++++++++++ src/python_docx_replace/paragraph.py | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/src/python_docx_replace/__init__.py b/src/python_docx_replace/__init__.py index f958e52..e3d2bae 100644 --- a/src/python_docx_replace/__init__.py +++ b/src/python_docx_replace/__init__.py @@ -2,6 +2,8 @@ from python_docx_replace.exceptions import EndTagNotFound, InitialTagNotFound, TableIndexNotFound from python_docx_replace.paragraph import Paragraph +from docx.opc.constants import RELATIONSHIP_TYPE + __all__ = ["docx_replace", "docx_blocks", "docx_remove_table"] @@ -26,6 +28,7 @@ def docx_replace(doc, **kwargs: str) -> None: for p in Paragraph.get_all(doc): paragraph = Paragraph(p) paragraph.replace_key(key, str(value)) + _replace_in_links(doc, key, str(value)) def docx_blocks(doc: Any, **kwargs: bool) -> None: @@ -145,3 +148,18 @@ def _search_for_lost_end_tag(doc: Any, initial: str, end: str) -> None: paragraph = Paragraph(p) if paragraph.contains(end): raise InitialTagNotFound(initial, end) + +def _replace_in_links(doc: Any, key: str, value: str): + # Make replacements in hyperlink targets + rel_dicts = [] + rel_dicts.append(doc.part.rels) + + for section in doc.sections: + rel_dicts.append(section.header.part.rels) + rel_dicts.append(section.footer.part.rels) + + for rels in rel_dicts: + for rel_id, rel in rels.items(): + if rel.reltype == RELATIONSHIP_TYPE.HYPERLINK: + if key in rel._target: + rel._target = rel._target.replace(key, value) diff --git a/src/python_docx_replace/paragraph.py b/src/python_docx_replace/paragraph.py index bd88772..328eaca 100644 --- a/src/python_docx_replace/paragraph.py +++ b/src/python_docx_replace/paragraph.py @@ -49,6 +49,14 @@ def replace_key(self, key, value) -> None: self._simple_replace_key(key, value) if key in self.p.text: self._complex_replace_key(key, value) + # Make replacements in hyperlink texts + for link in self.p._element.xpath(".//w:hyperlink"): + try: + inner_run = link.xpath("w:r", namespaces=link.nsmap)[0] + except IndexError: + continue + if key in inner_run.text: + inner_run.text = inner_run.text.replace(key, value) def replace_block(self, initial, end, keep_block) -> None: block_handler = BlockHandler(self.p) From d374e42d87cd34a122fb6288f37f68fe166582a1 Mon Sep 17 00:00:00 2001 From: Benjamin Dabelow <2276720+bdabelow@users.noreply.github.com> Date: Thu, 30 Mar 2023 22:41:35 +0200 Subject: [PATCH 2/4] Ammend tests to also test link replacement --- .gitignore | 3 +++ test/app.py | 2 +- test/hello.docx | Bin 16882 -> 12233 bytes 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5e43896..394facb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Testing +/test/hello2.docx + # Mac / IDE .DS_Store .idea diff --git a/test/app.py b/test/app.py index eeac831..6c7232f 100644 --- a/test/app.py +++ b/test/app.py @@ -5,7 +5,7 @@ def manual_test(): doc = Document("test/hello.docx") - docx_replace(doc, name="Ivan Bicalho") + docx_replace(doc, name="Ivan Bicalho", github_name="ivanbicalho") docx_blocks(doc, block=True) docx_remove_table(doc, 0) diff --git a/test/hello.docx b/test/hello.docx index b870cc0cb8c2144b6c748abbc8fb301c050eb230..2cc09f5b60ac9ab931adcb3bf6f7ce8d4aee7e26 100644 GIT binary patch literal 12233 zcmd^lWmsIv)-LWY!GpWIOK^9W;2PXrgF|q42<`zI3&9L9NQJn*-^qp7tMBg4zJaEjhbK;)nqO(PH=y4G#wfj^730y;ky2Sya0j5{F zefNnaGOX*S;}2&^R(l*~*d`d$IK0#-mr2{)^Ncdt`P$i;f zb%$7|Brk>RC%`IRNG-ZfNs~;VFtnrIQpC^LMMMr=?{h>0=>Zsx_2%vDtv)7>AW|MJ zX=cszEP5SqYNkZRfE%P@sfhN5x7Irh0v2hkriH&II>am$kPa1!p*A+`C6Tmf5g&{1 zOg*0GKjG4@R7iu+P!x-&)^zX>P+`|p>5lQ4b6(AWVJ0f#CMac^(F)_p;Sg7&|2pz9 zp6_j-KfTeFU?q2NuEg6BVk3c-*EIFM8_Os610iN?UOn!*gonNO1xP|rys9L3^Tk0j zs1*ACsdEc#)=eX;=DB~^D83g*Ya+^&x?rpB!ZQf)CAiJ%v?h1XW`@{q(Y3YF4dq*g zrKIq25@TM_&+{>dH~KGgb~kHDgF+1gK2W7TT-@DR| zH$fA4RA-bHg3<3uyt(f$4%r`NkWALj?pE!Hy=)46&6luV#nw_hPW-!Q_E)%uP%!R?26E15JZ9TO4CK`7o3p;BCN!}75^5H=UppIAbJ}^=^ z(2?BgD<^FffnBaK1JW0`A*rQL_aHXW*9To- z4kp7^_H44O7~8p(_Voj>Z)q+knTDH?eOvYqV6!ct4>AN{!yRsfO2=Ub2MT6*G_3+YG`8W$owMx-(}$JYWL#J%oEnl(Bi2g?$!`7#PUMl5?<|k#We1Jvc-Uo z81%F?(4HX*OFE-Jg8Bv^OmN#@Oz8~~Pm3hS!HcI7%*18l4&^pd4#|{FLhjjNx!X5k zV6j3_KKV@HU4DeqCjnKjAX|Hi7k1)Gvx>SWNHUJ0j8A_Crz$RY z|7nIJ<58jTYxmq$^_|(lzN3@x!?#3D0#>nPQiC**91e@>7bVmJ=c()g4)sMK|6K|H zCJZw>JLms@g@ON9%>W)0E;gpN&VQ)JOd_*FHxo+m?Nh{n5xG2kqB1!>IFXCNJ45kL zPExYQykDwIFgM$c(^cg@qXl3<^|=YO-yT@&H7yTKdVw1UtE1xl1icV)$bw6f*yi@- z%8A=C!Vq{jINmTXtUBxDmKZG=pgBt2@D*gRqMBCmlx#|z#d&hO-pG5@F*kuIRe9=$ zDDqQrqco|J`a!DuMO9#q`w<;F{wdpmpHTLFRLelr1<@S>Ie4R=$5K#lwY`A=H;a!mhT zqOYgmL~F%%i38)?nu@*fL^<~t0^Y&tMXmH)sqxS7hxKiAR1xu9DxZavT{Df4>&zD- zqcN`07vy()G>bs4gUK&r_q_K~cqW&+Gd>35yotBxaP;KWgEk0p7t&;N6wq%!!{-vB z832>y?j|)4D0Jd_IyhN|=NdvA!5GI+{c$%i2ysOg;Q(ezNi1nUC^GYo@4_7$?PFx5 z$}tKlr8>>EZsUA?x5@|`{WeK}G_u(CB0Xg=UE|uxX)~Bg3EO*|1l8naGvvV>@_Jp) zHPOS&NFq#pL+S=%G^-to*qR8r>ehg+5QPTP6;Vf`^-Os$Qfq=H1B@qR`uaYH&3(Ir}Iy!-K^zqW8hG~xNxfSi+H2)1oP%~$c^R_oz zQNgDVR9y_Yv0~&nb>H{G^I9MmD(}MN8b|oq1-cU*&kuQnV4tqcMU-6wcIM%t+Nau| z!KzC=w^TkARg+#rDR$XcXIUWD`+DV_0MOGNs&(#fy`i*t9bDgDeJF-2KX5kuQhE@e zFEp|T0*CO1k9S!;E)-=g*mYucx!J<*^lMbj2T@&KV!#hkOH1*3Haw`4kL=cz6=pMb zlzk}<^&ELrId4*g;d3}Z^fLO^RbxAhCbz58KjY2nyM?we&apto>IoUwhkV>qeNv+T##qSeX1}NPS+SEF$6n0 z^gs(7oCN4GPmv71CtcLJ#X<%n^tI0`jYSEQeCF9@lhI@r$y3d740oZyyI-lSO(SyXC$U+zs+37+u?kV*_!zw_e){NQ zV~4=OJNen&3GgHLdLb?dbuLy)#COCwAy8jHGRMc^bE|h@z^jWX1>68K_mPLvjGOry zBT9)Y(l4ci#E~$v1}7XRT69579lho996yAv?cF>Q+OFmQdSW`i!k%w{9IgD+`i7u` z5o`!LJESpH@hd?(uS@^e<`EHz{>X4m>2 z#np+jZAE&hv3Af(u11vW93vb;o>vAH)-N-C*GAA|G`3c`()R;D_wHP+Lgm%9y6k)Z zL^djrbA78XEDWm4vU3%N^n_e`1WwD;zd?b@KF^b%UbxrTLe)S#Ig5oB9`}XT7~z_9 zkP_c00H^Dk6#>amJV^!5$|B%nX89-wMq4zo#%VX_A)I)yyd_&ReM^(CU#wtM&x5Z! z(|$6%GdQ$$dkHLfE5+HcWNtX-D-3zWzs4OB`;dqeTGoc;Y7!=BhGS8U9OOw6hR*~xPGNN znLbm;bC_Q6s`(oF$A#d_9$8p8F}?!<0uoI4PkZEx`S^Q}e064zCdx!EF`@VaZ5QEV zc89O^g{dw#UyeBvg^64D@&}A{L>a{$mz@v%s<$=X(vvTp$7IR2?Tq|sm0@kUUh5$4qsa+N!W5Ltt~+8x za~c|cG;3jwLjj9Qa$vW8o(R-#{mrVG6bspCG$esh;k#aM_a2%9l~V*e42v9H#y4l^ z5QE-|E)6xdpHH4t{ff7ns@gtVeW8uA+$~V!`P)d( z!)M|L4+Sg73XUgU-T@C+Ew94ao;Dbp@R&vc|4%$lD{Py3LS z#Y*Fe$5^8E`?tD-f)?CIMOmzv5~x8c#Y#*lQtlP-;-o%d$6iqZhWTx?uC#2H=mNO8Vx%Bc5vs6VN4mOW`b zvpnk#l8pt1V$s0|bK&WI(WFbnKAYO0bM?vJVL7oW*Bj? z)F+73$zT+%2mip%ycgotXBt;`_TXPlCxAyFpFy9p@B~ODcN^u%=4-uc(gAHdnEJY0 zKiyidtO@VUoa3%&&a_&A`86>pK zEFEiPCdJ{%-k=s+^cd2T)RpOHnN**m{|Nu&I~`smcqlsNHyv&U{O$)TF8`UzSf8}$wpGp zTMe=#vJO>#9exz#qTrEVP;V#QOb&Rn_e}e+225)(+=9Q0LSbc6>U&fqjQNWxr7etu zVvfNljo;UA%2YYej!_e2AmK)SgqEs(k8)==bUL8P7ao>TO&sqGhZkxl_Kl`M9EIyT zJy;s;$9+_VpF8cB4I4G#z(|r$+^9$V(UCZ_=gS=iA;nNotbD9YsT<(|g*a;HGi>?E zWtO6d>QiBhm6r--uH}}ZC%k<2i?lW9s6)RdTm+7X<}u zAR^bgd8X^ik5^eJUc>P(ZTNtlxv9X8swI;S!%47>%W=lZ0zv9nTkn61tl z8+Sc;#HpFWcvb`K`6-z3>77c4Qx*hejA#QtWecB)K}w)OY^fv*3CV$FktD<*wv~JP zWq+^G7-0~*hs7ZvFeuQWS<4nu40K7CE@jMGipL}u>( ztV%+H-rZ4>$izg0gAgSR4o-?`aEH$G#`@0qsX){b!*cYzk`2EF2*AC|7R^&Qk zSv*%e9z(*Qj9EABT9@j}m6rzJ7IjY=nd^cm=`%k1^dBFf0~+p+Ypys{$Rb=+6z_f< zAD6Tlua?3E#Eu__S?jSlW;OY=_X_=TAe*$`ROozIdRn|0r)tDH>H{2r_g@Af4Dp{n!>Jma zVwS`P{=4ta_vSv4lh>(_5PmaL_dNoe{5fTcgeMx!ZdG|V66}SJbr0>4_QX3r;}4q~ z6H0zznmxklGSe|2BIgi2p)x-a39C){9@GncvAUL7Ayb%&eds&clPpt)my(GFGh97d zY+%i@rm9xw01(~l_2pCS4hwvV`Jto+%QK^zedwVc8g@2m-4v&X1@t2GU3&a=rZ9L- z<$?f&9B9+MuXc}L&3Q*T#!|q9Q+TyM8gu3i)90yw|M0U-%nALWY>(nc(uADQ!9mY@ zuuH)>T&t3=ayL`A^a){!EttBMW~0Ioh>Gc_th$VKa`uip z8APR3Ws$_3X?v<}X+&7fQesfr>kiO`@QW1O{I5Vd!P1RwBwBVdgWq(qeuc=>n!H*co)J58%6BQ?g?F05{4yr0qNPOogxFrSGm@jS}c&4`@SA21pQx?=CzL!;G3QatpoTgaZ< z^iAN0u|LrCIk&21oHa||;K4qg0N8HtT{9d|_r*7)e=5ya$jmk=wdJ4hCN-JyZy*&r z(g|Bjx1Z>y7aZ9GW796n@?;>-^#UTH)yfTTP6}7ew;8_ZR>@g6s1@;WF-d5wjyeYj zka;Do*bqvnDJU3zE|nF<6XXiJyE;(f!qs6wzJ8m#n{@wHa;!`P`ng)Q%{xqjobP#P z#wVU3avRC24JYte`559n;OXr1r@8zEO$M;HSH!`s>sqK)j;jT+_C9Lnh6+QINYvIp z2OK-q-c%)y`~2|Tc=}~ryRxv$dgGsv7`ZXKG~A1Lnp73%MAx#%=VPa3-H*rBgfD-x zVe05U{(;GZ)_J3x9e$5)u;N{z=@_8jhtbKB1Nv%s-IYAvEVWrVGo$;~>oy^I_0c4Z zWNCH@%cNEDr-~Ju{>d_%Su?^$fBrG+*6Ft<( zhesRCMJLjut$dr7v&d~il!oEPr0XwFixVm*Ynzv&)-q#Q9@i5=BOB)lB8lB1XBacj zjCHH5sB3)>BQtIcU1}sOK;`AL7peS5Ay$7&u~@zlu85aq${B4w&BFsF-b zdxOeX3a#NZ;OuHdLdrqTk4Mh3(IL+6_7F9AFi|mMvYZ$u37gWWI>nHPG+TfA%+usj z@(pd)yU`$ninF}OnPRBZb=-lIks{I|g_V(U>=@I+yovF4?i&caRplmMQ~f^ytmBM6@r*L~#py`?mU7Fwz ze1AIzf@zym)7FXZ;TEOgVa@#om!9g-G`|~G!ZQxP3_^B4Q^sfT7spO}n!hX)5d=gn z;GZ13KOz9HQW(GpK+F^qO8=QRobgG6TpifQe7V~%Mx`id%5Gz{b7^GikCXG3RJ7lC zUElloD;gpbiAhzY-H-b98Lut-s>L6JWHIp+A9%lmwXlWDE6)@V@J?+j?(rysr-%;8 zJnfuV+9}WAD2FE_)@&Wwu78)s{XWRZwg^IEOZLEgxnv}dhvaL}o9^svn z@jGZ8OGReFWKD9Pfvk;au#<$N-c7wgqBLY>J^Bhf%ht7>HEQmMh7=PU#5Zpcq4$K5 z6OXTGD1LmD!otG9=T`aHM&=Yy!7uGWvt7mcHtdvgo6PvF3Bt+|RX_^EclV=oEw1sh zl!?;`HrLP8zETYl8-UtcV~*o}amkHay$xukgN&3?p0kCui%+|hK0nQ0hX7C@$;px> zz~UIXwZ5zz!Mo-(tjQ4B0E}6RbE4?m1As9Ai=I^p7QN`Vx#lrP7IIKdEP3aXvA`HW zC@==_Rv)}H0Moy^VCD8b|Bc_ozk&ce@A>=N&z{8(LdowiF%2yJJy2rGEJIE%LLvhw*MPR6Y};tkFF^6`w~sU)5GZ;$%9;NMtxAmKSC z^hgK@TpsM+w7T`e7s=vVv1X|jb&S^(p6g~XX6*Fxs+a^AbUJh_BBYLvtaj#1^8 z=voBF?)libk~q9iZeGX><=Y5*XG~9toIm$N_a@U?cG=*2`k@|od0F`+IAq;;eD%n; z{XJBbpm+6I!?#7t&~$)t?u8CldVI`FuquwZxRfWC*4X8}1?6W8R=j0+$mlx*T=0O=+i65_h~jqXM-br4fM(Nn}~i zhBj2F4APe(jj!-GA}PW3n^c>EJa; z!RAswf*wU5#e{%$n{z7#qjk#i&gQ0(UW@!uYx7PAOAwd=g@%#**ew|eoXN|7oJq|8 ztQThsQyWvp-`C&S;S;S^8AOt}g zVb^>x0YksA7PUZV+MgW9R<@_B@0qWWtF!6>A#X|c$L6?hEkK3KomEgfT!P=xqx**T zeKG)KDu^hfmMYFL)R^|skagF%i~w|bx|dJHaXFMycaF(Gm(SwR>}DeR<_c{g zP?z!N$j&ZUcP%h`U|)mbtT$E(NPalceWs|=IZ|((Dg1^25-3zLt-N2c@Qt_sjgW^* zUaQIxSMo>3eK(GCddA0u^Y3tHw(DN}ex}`ERCb0>aoa03rF28!MQesg%d8OUEoxIq+ko5DSgq?RTVHqPEu<_9r(fvo7{R>35>R|B$ zgx0G$iN;aWHUdL@#RQUB}H(^0#xZ;^i^6*k6(4~9t5NkKR>)bm8T>*jgu}Ud>6he@P+}JSe9sR(%b|gPxzQvI9~5o zQ3#flw2EI;8;__^>cOI8MwplCjc-~h44j_~V8JW50am^Atb-JX`Ua|lCJ9Bx>?>>$ zevfn?QJ>g0!+KoAc4rh+d?yZ8HWD#~wi^tN%HVP#Yxt>6oY}PPT6dkMxbmkynr#N6 z&tb>0wS)og`P)(PC1H=5(PCj>HaYg>uq0=(^^Ctj;+5S5g<^B;?AEX>B?*WQ5~$T| zU?sO7xw=U~)P{7}l9jC^NlcyVi}NrRTTzVc5kgR`ZUr?q20xZatwo5cF9gsmErU5$ z6g@()DA5-7Mt9YQNfCR2h$wfN+X0f@&4|K5>8HHS=|W{S@Lg(I-a9ZQD^uqm6saXN z4I9~0RQ^Pb?V>qhb@}?;!f}e!T$!oD_Roe~OAE`wv?4$TR zh{-|ACiqZ&k1J2#Ei1YgoMkipd0!UaTxL>5llEK@uZ77dej%n%M9$!I#43zUc#ad& zN=NIJI{&jf8+(K&ZTymaiVSV^-WiSIGtq|+iRX+cF-Rm#s8gB?2*erXNNF6zvKaE7 zrKc6=>3v=%sWIBKn{7oXAl~c@aMis{R8#H(+Le{>*Xd`>+hQ?c-P0!P5~yS;66`U^ ztiCTuYVL~FT2N_DSGv_Q!M#TfO@NxjTF=g4Mcbed_Dp@CPSJP2?c&!nll52t7vR_IZ4qng-u+5><{b8P`c{DUlBfVoU>Q_N12(_E5Q2DQIZeMIn1=*qcBv z)7}PW_O*yfpJA&=Fuw4PU!v3$SNPctDb8?51F2QjLyBqkC^rn7(?0Fv+LLtLLRN)Z z$CpU=V6+mWLn^y1;w#>_)E5`f!U5WPa-&Krw7k3wHAGah8uYapdWWMie2B9JvsBYb zT6SAT83;&X+is!_JiVDa)qV1!_a}^1WLL7W(F|XPVdsi4*smpu<{W*Nu4v6xj?{Jg z*=b#>cT}~r_cZm!Sa@xI0;L^eG(5a_8t!*{O+u}8&K~!~s&J#;6SHxuN(0xoLGM8IQM-8VqRq45R&(wXOU;s_cjIEE zMp^Qi#&TKOWHl!Z`y4>Wwo>h^rLx~iCo+lA7i)La-R2qoXi(4w#EVQ=cB_mT}9Pd!RX)!6`X@yCH4HyAo_;j!JXH4%l9N|0p~D zWggUi!)-U`mR5l6hs+_E)qDHp5Ob7~G>0+Sb+CtBH{k--v*MVzjRCGS1c4odFW?LMLnby~$ZHTrdfe>8 zV|llAsc!|hPv#lIPlXkR7F!KRs5K+aiBAo5P@{%B1$c}F?eL;6h}K%g z$${2F-f*CSA`J5~lb~Q2Ab-MqU*lU}V7`AXuRyRb*B;f2 zclu|+Ao`=@uYA?N)4#Uk|0*|6;{SC0l^6DR^4I(2i?RP_5heXM`QJ_dzq5F~Q2)9p c@M!+mZB|hR5~yV$AjrVacc9wu(7xRLA0mpen*aa+ literal 16882 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 From c33f0753345ecef41cf638caf789f48c631a0e3f Mon Sep 17 00:00:00 2001 From: Benjamin Dabelow <2276720+bdabelow@users.noreply.github.com> Date: Wed, 12 Apr 2023 00:35:42 +0200 Subject: [PATCH 3/4] Factor out _replace_hyperlinks() --- src/python_docx_replace/paragraph.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/python_docx_replace/paragraph.py b/src/python_docx_replace/paragraph.py index 328eaca..98efc00 100644 --- a/src/python_docx_replace/paragraph.py +++ b/src/python_docx_replace/paragraph.py @@ -49,14 +49,7 @@ def replace_key(self, key, value) -> None: self._simple_replace_key(key, value) if key in self.p.text: self._complex_replace_key(key, value) - # Make replacements in hyperlink texts - for link in self.p._element.xpath(".//w:hyperlink"): - try: - inner_run = link.xpath("w:r", namespaces=link.nsmap)[0] - except IndexError: - continue - if key in inner_run.text: - inner_run.text = inner_run.text.replace(key, value) + self._replace_hyperlinks(key, value) def replace_block(self, initial, end, keep_block) -> None: block_handler = BlockHandler(self.p) @@ -82,3 +75,13 @@ def _complex_replace_key(self, key, value) -> None: # if the key appears more than once in the paragraph, it will replaced all key_changer = KeyChanger(self.p, key, value) key_changer.replace() + + def _replace_hyperlinks(self, key, value) -> None: + # Make replacements in hyperlink texts + for link in self.p._element.xpath(".//w:hyperlink"): + try: + inner_run = link.xpath("w:r", namespaces=link.nsmap)[0] + except IndexError: + continue + if key in inner_run.text: + inner_run.text = inner_run.text.replace(key, value) From f11090324b53f31fba6c206a512b86f42d8b24cb Mon Sep 17 00:00:00 2001 From: Ivan Bicalho Date: Sat, 22 Apr 2023 18:33:32 -0300 Subject: [PATCH 4/4] fix _replace_in_links --- .gitignore | 3 --- src/python_docx_replace/__init__.py | 7 ++++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 394facb..5e43896 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# Testing -/test/hello2.docx - # Mac / IDE .DS_Store .idea diff --git a/src/python_docx_replace/__init__.py b/src/python_docx_replace/__init__.py index e3d2bae..40aff4f 100644 --- a/src/python_docx_replace/__init__.py +++ b/src/python_docx_replace/__init__.py @@ -3,7 +3,7 @@ from python_docx_replace.exceptions import EndTagNotFound, InitialTagNotFound, TableIndexNotFound from python_docx_replace.paragraph import Paragraph from docx.opc.constants import RELATIONSHIP_TYPE - +import urllib.parse __all__ = ["docx_replace", "docx_blocks", "docx_remove_table"] @@ -161,5 +161,6 @@ def _replace_in_links(doc: Any, key: str, value: str): for rels in rel_dicts: for rel_id, rel in rels.items(): if rel.reltype == RELATIONSHIP_TYPE.HYPERLINK: - if key in rel._target: - rel._target = rel._target.replace(key, value) + target = urllib.parse.unquote(rel._target) + if key in target: + rel._target = urllib.parse.quote(target.replace(key, value))