3

I am transferring an Android SMS database to my iPhone manually without restoring. Because of the number format of +1562... the iPhone does not recognize the format and creates a new text thread.

I am trying to change +15629876543 to 5629876543 and +17114747474 to 7114747474, and so on.

There are thousands more numbers ranging in size. Any other number that has more than or less than 10 digits, should be untouched.

This seems to be a step in the right direction:

grep -P '(?<!\d)\d{4}(?!\d)' file

retrieved from How to grep for groups of n digits, but no more than n?

Here is a sample of the XML file (EDIT: I added a root element named <root> to make the XML well-formed).

<root>
    <sms>
        <address>+15629876543</address>
        <date>1554966601000</date>
        <type>1</type>
        <body> Yea, should be true. </body>
        <mmsReaded>1</mmsReaded>
        <attachments />
    </sms>
    <sms>
        <isMms>1</isMms>
        <date>1554968044000</date>
        <type>2</type>
        <mmsMsgBox>2</mmsMsgBox>
        <mmsReaded>1</mmsReaded>
        <attachments>
            <attachment>
                <type>image/jpeg</type>
                <body></body>
                <name>Screenshot_20190411-002704_Flud.jpg</name>
            </attachment>
        </attachments>
    </sms>
    <sms>
        <isMms>0</isMms>
        <address>+15621234567</address>
        <date>1554968778000</date>
        <type>1</type>
        <isMms>0</isMms>
        <address>+17141234534</address>
        <date>1558919932000</date>
        <type>1</type>
        <body>:)</body>
        <mmsReaded>1</mmsReaded>
        <attachments />
    </sms>
    <sms>
        <isMms>0</isMms>
        <address>+17141234567</address>
        <date>1558927846000</date>
        <type>1</type>
        <body>It&apos;s so</body>
        <mmsReaded>1</mmsReaded>
        <attachments />
        <isMms>0</isMms>
        <address>+17145757575</address>
        <date>1543704644000</date>
        <type>1</type>
        <body>Hey</body>
        <mmsReaded>1</mmsReaded>
        <attachments />
    </sms>
    <sms>
        <isMms>0</isMms>
        <date>1543704676000</date>
        <type>2</type>
        <body>More text</body>
        <mmsReaded>1</mmsReaded>
        <attachments />
    </sms>
    <sms>
        <isMms>0</isMms>
        <address>+17142323232</address>
        <date>1543704736000</date>
        <type>1</type>
        <body>Lol not even</body>
        <mmsReaded>1</mmsReaded>
        <attachments />
    </sms>
    <sms>
        <isMms>0</isMms>
        <address>+17141010101</address>
        <date>1543704748000</date>
        <type>1</type>
        <body>You do</body>
        <mmsReaded>1</mmsReaded>
        <attachments />
    </sms>
</root>
zx485
  • 2,865
abolodo
  • 31

2 Answers2

1

Be very careful when using sed to edit XML files. (It's risky).

But you can easily use an XSLT-1.0 processor like xsltproc or Saxon to remove the leading +1 string from the <address> element. So use the following XSLT file

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" /> 
  <xsl:output method="xml" indent="yes" /> 

    <!-- Identity template -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>  

    <xsl:template match="sms/address[starts-with(.,'+1')]">
        <xsl:copy>
            <xsl:value-of select="substring(.,3)"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

with your XML and the result (with the XML from your question) is:

<root>
    <sms>
        <address>5629876543</address>
        <date>1554966601000</date>
        <type>1</type>
        <body> Yea, should be true. </body>
        <mmsReaded>1</mmsReaded>
        <attachments/>
    </sms>
    <sms>
        <isMms>1</isMms>
        <date>1554968044000</date>
        <type>2</type>
        <mmsMsgBox>2</mmsMsgBox>
        <mmsReaded>1</mmsReaded>
        <attachments>
            <attachment>
                <type>image/jpeg</type>
                <body/>
                <name>Screenshot_20190411-002704_Flud.jpg</name>
            </attachment>
        </attachments>
    </sms>
    <sms>
        <isMms>0</isMms>
        <address>5621234567</address>
        <date>1554968778000</date>
        <type>1</type>
        <isMms>0</isMms>
        <address>7141234534</address>
        <date>1558919932000</date>
        <type>1</type>
        <body>:)</body>
        <mmsReaded>1</mmsReaded>
        <attachments/>
    </sms>
    <sms>
        <isMms>0</isMms>
        <address>7141234567</address>
        <date>1558927846000</date>
        <type>1</type>
        <body>It's so</body>
        <mmsReaded>1</mmsReaded>
        <attachments/>
        <isMms>0</isMms>
        <address>7145757575</address>
        <date>1543704644000</date>
        <type>1</type>
        <body>Hey</body>
        <mmsReaded>1</mmsReaded>
        <attachments/>
    </sms>
    <sms>
        <isMms>0</isMms>
        <date>1543704676000</date>
        <type>2</type>
        <body>More text</body>
        <mmsReaded>1</mmsReaded>
        <attachments/>
    </sms>
    <sms>
        <isMms>0</isMms>
        <address>7142323232</address>
        <date>1543704736000</date>
        <type>1</type>
        <body>Lol not even</body>
        <mmsReaded>1</mmsReaded>
        <attachments/>
    </sms>
    <sms>
        <isMms>0</isMms>
        <address>7141010101</address>
        <date>1543704748000</date>
        <type>1</type>
        <body>You do</body>
        <mmsReaded>1</mmsReaded>
        <attachments/>
    </sms>
</root>

This should be as desired.

zx485
  • 2,865
0

Yes, you should generally avoid using regular expressions to parse structured data. But this is a pretty simple case if you are 100% that all occurrences of + followed 11 digits are valid targets. You can tell sed to only remove + if it is followed by 11 numbers (I assume you meant 11 not 10, since you have 11 in your data):

sed -E 's/\+([0-9]{11}[^0-9]*)\b/\1/' file.xml 

The -E enables extended regular expressions which give a simplified syntax and the ability to use {N} to mean "match N times". So here, we are matching a + (this needs to be escaped as \+ since otherwise it means "match 1 or more") that is followed by exactly 11 numbers, then 0 or more non-numbers until the first word boundary (\b).

The entire match except the + is captured in parentheses, so \1, the replacement, is everything except the +.


A slightly safer approach, since all of your target numbers seem to be in address tags, would be:

sed -E 's|<address>\+([0-9]{11})<\/address>|<address>\1</address>|' file.xml 

Or even, if your problem can be restated as "remove all + from lines where the first non-space string is <address>", you could do:

sed -E '/<address>+/{s/\+//}' file.xml
terdon
  • 104,119