text: user16328: I have a FASTA file that has reads like this:
  
  >SRR5655563.745 745 length=126 (type=T,start=2,end=12,length=11,identity=81.8182%) CttttatttgttGTGTGTGAGGTTTGATTTGATGGGAAAATATCTTGAATCTGCGGCGAGGTTGGAAGAGCTATCGCGGATTGTGTCATCTGCTGCGAAGCCCAATAGGTCAAAGGGAACGCTACC
  
  As you can see, there is information about the start "start=2" and end "end=12" of a sequence within the header. I would like to slice the sequence like [start:end] and keep the rest of it. e.g
  The part I would like to trim:
  
  Ctttggtttcctttt
  
  And after trimming, I would like to keep the rest of the read:
  
  GTGTGTGAGGTTTGATTTGATGGGAAAATATCTTGAATCTGCGGCGAGGTTGGAAGAGCTATCGCGGATTGTGTCATCTGCTGCGAAGCCCAATAGGTCAAAGGGAACGCTACC
  
  So the new FASTA file will have reads like this:
  
  >SRR5655563.745 745 length=126 (type=T,start=2,end=12,length=11,identity=81.8182%)
  GTGTGTGAGGTTTGATTTGATGGGAAAATATCTTGAATCTGCGGCGAGGTTGGAAGAGCTATCGCGGATTGTGTCATCTGCTGCGAAGCCCAATAGGTCAAAGGGAACGCTACC
  
  I have written a python script that takes a FASTA file as an input and outputs a trimmed FASTA file, like this:
  tailtrim.py --fasta input.fasta --output output.tail.trimmed.fasta
  
  The code does trim the reads where I want it to.
  import numpy as np
  import argparse
  import re
  
  def main():
      parser = argparse.ArgumentParser()
  
      parser.add_argument("--fasta", type=str, required=True, help="input fasta file")
      parser.add_argument("--output", type=str, required=True, help="output tail.trimmed.fasta file")
  
      args = parser.parse_args()
  
      out_fasta = open(args.tail.trimmed.fasta, 'w')
  
      for line in open(args.fasta):
          header = line.rstrip()
          read = next(args.fasta).rstrip()
  
      #Extract header into a list
          header_lst = []
          header_lst= header.split(" ")
      
          tmp_start_lst = []
          tmp_end_lst = []
          tmp_lst = []
  
          for i in header_lst:
              if i.startswith("(") and i.endswith(")"):
                  tmp_lst.append(i.split(","))
          #print(tmp_lst)
  
      # Extract the start and end numbers in a list
          for i in tmp_lst:
              for str in i: 
                  if str.startswith("start="):
                      tmp_start_lst.append(str)
                  if str.startswith("end="):
                      tmp_end_lst.append(str)
  
          pattern = re.compile(r'\d+$')
  
          start_lst = []
          for str in tmp_start_lst:
              match = re.search(pattern, str)
              start_lst.append(int(match.group()))
  
          end_lst = []
          for str in tmp_end_lst:
              match = re.search(pattern, str)
              end_lst.append(int(match.group()))
  
          #Extract reads into a list to manipulate i.e. trim
          read_lst = []
          read_lst.append(read)
  
          new_lst = []
          
          for str in read_lst:
              for num_start in start_lst:
                  for num_end in end_lst:
                      s = str.replace(str[(num_start-1):num_end],"")
                      new_lst.append(s)
          
  
  I do get the trimmed reads, but what I'm having trouble figuring out is how to write these trimmed reads with their corresponding headers to a new FASTA file.
  Also if there is any way that I could improve my code or employ better strategy to approach the problem, I would love to know.
  Best wishes.
  Edit: I tried running the solution by the super helpful user @Steve.
  The command I ran:
  python3 tailTrimming.py --fasta tailtrim.fasta --output testtrim.trim.fasta
  
  The command line error:
  Traceback (most recent call last):
    File "/home/x/Desktop/fastq/tailTrimming.py", line 61, in <module>
      main()
    File "/home/x/Desktop/fastq/tailTrimming.py", line 58, in main
      SeqIO.write(trim_reads(fasta), out, "fasta")
    File "/home/x/.local/lib/python3.10/site-packages/Bio/SeqIO/__init__.py", line 478, in write
      count = writer_class(fp).write_file(sequences)
    File "/home/x/.local/lib/python3.10/site-packages/Bio/SeqIO/Interfaces.py", line 209, in write_file
      count = self.write_records(records)
    File "/home/x/.local/lib/python3.10/site-packages/Bio/SeqIO/Interfaces.py", line 193, in write_records
      for record in records:
    File "/home/x/Desktop/fastq/tailTrimming.py", line 20, in trim_reads
      result = match.groupdict()
  AttributeError: 'NoneType' object has no attribute 'groupdict'
  
  This is the whole input file I supplied:
  >SRR5655563.9676 9676 length=126 (type=T,start=1,end=11,length=11,identity=81.8182%)
  tttctttctttAGTTCCAATAGTCTTGACCACCTTTTATCAACAGAAGCTTGGCCTTGTCCAGTTATATATTGTATTGTACCCTCAGATTTCTCGCACAAT
  >SRR5655563.10087 10087 length=126 (type=T,start=2,end=16,length=15,identity=80%)
  GtttgtttcattttttCCAAGGAAGAAATTCGACCTTCCAGCGATTTGTGGAGGTCATTCATCTGTTGAGTAAAGGATTGGTGCGCGACCTTGTAATCCTTGTGGAGGGTGTAG
  >SRR5655563.13902 13902 length=126 (type=T,start=2,end=16,length=15,identity=80%)
  CtttttcttcttgtttGATGTAAAAAATCTTCGGTATCTAAAACGTATGAAACCTTAGATGAACTGCAAGCTATCTTACACTCTAGACCATTGATAATTT
  >SRR5655563.18489 18489 length=126 (type=T,start=2,end=12,length=11,identity=81.8182%)
  CtttttcttcttCTTGGAAGTTTTGGATTCTGCAGGGACATTTTCTTTCTTTTCTCCATCTCCATCAGTCTCAACACCTGTCTTATCCTGAGCACCTTGAGACTCATCTTGACCATCTTTACTTT
  >SRR5655563.20782 20782 length=126 (type=T,start=2,end=15,length=14,identity=71.4286%)
  CttcattttagttttCAACTCCTCTACCAACTGGGATGGTGCATTCAACTGTAGAACTGTTTCACGAATCTCCTTGAGAACACTGAAGTCTCCCTCAGTTAACTTCTTTTTCAAATTATTGA
  >SRR5655563.23972 23972 length=126 (type=T,start=2,end=29,length=28,identity=75%)
  CttttttgttgttctcttctttcttctttGCATGGCTTGATGATGACTGATCCGATTGATTATTTCTTGATAGAATATCAATGTCATCACCAATTGTTGAGT
  >SRR5655563.31739 31739 length=126 (type=T,start=1,end=10,length=10,identity=80%)
  ttttcttcttCTTGCATGAAAGTGGGTTTGGACCCTTAGCTCTTTTTCTCTTGAACTGAGGTTT
  >SRR5655563.34244 34244 length=126 (type=T,start=2,end=14,length=13,identity=76.9231%)
  CtttcctttattttCTTGGAGGTTAGCCAGGATATTGGGATCAAAGCATGTAGCAAAACACACCTTGCTATTTCTTGCTCGTACAGATACATGGGATAGGA
  >SRR5655563.38334 38334 length=126 (type=T,start=2,end=12,length=11,identity=81.8182%)
  CtttattgttttCTCATCACCCATATTATATTTCTTAAGGGCAGATTCCAACTCTTCCATTGTGATGTACCCGCTCTTATCATTGTCAAAATATTCAAAGGCTTTATATAGGCGATCCTCTCTTTC
  
  And this is the whole output I have gotten:
  >SRR5655563.9676 9676 length=126 (type=T,start=1,end=11,length=11,identity=81.8182%)
  AGTTCCAATAGTCTTGACCACCTTTTATCAACAGAAGCTTGGCCTTGTCCAGTTATATAT
  TGTATTGTACCCTCAGATTTCTCGCACAAT
  
  Just one read, that's all. Whereas I would like to keep all the sequences because all of them have this start, end attribute. The sequence being on two lines in the output is not something I did. It is like this in the output file. So it's no longer FASTA file, right?
  Thanks in advance for any help!
  
  user10775: Here's one way using Biopython and the SeqIO interface to read and write SeqRecord objects. Using a generator, we can produce (yield) trimmed sequence records that can then be written to the output handle. This avoids storing an entire list of trimmed sequences in memory and is usually the way to go, assuming you're dealing with large files containing thousands of records:
  import argparse
  import re
  
  from Bio import SeqIO
  
  def trim_reads(fileobj):
  
      pattern = (
          r'type=(?P<type>\w+),'
          r'start=(?P<start>\d+),'
          r'end=(?P<end>\d+),'
          r'length=(?P<length>\d+),'
          r'identity=(?P<identity>\d+(?:\.\d+)?)%'
      )
  
      for seq_record in SeqIO.parse(fileobj, "fasta"):
          match = re.search(pattern, seq_record.description)
          result = match.groupdict()
  
          start = int(result['start']) - 1
          end = int(result['end'])
  
          head = seq_record.seq[:start]
          tail = seq_record.seq[end:]
  
          seq_record.seq = head + tail
  
          yield seq_record
  
  def get_argument_parser():
  
      parser = argparse.ArgumentParser()
  
      parser.add_argument(
          "--fasta",
           type=str,
           required=True,
           help="input fasta file",
      )
      parser.add_argument(
          "--output",
          type=str,
          required=True,
          help="output tail.trimmed.fasta file",
      )
  
      return parser
  
  def main():
  
      parser = get_argument_parser()
      args = parser.parse_args()
  
      with open(args.fasta) as fasta, open(args.output, "w") as out:
          SeqIO.write(trim_reads(fasta), out, "fasta-2line")
  
  if __name__ == "__main__":
      main()
  
  
original_text: 16328: <p>I have a FASTA file that has reads like this:</p>
  <blockquote>
  <p>&gt;SRR5655563.745 745 length=126 (type=T,start=2,end=12,length=11,identity=81.8182%) CttttatttgttGTGTGTGAGGTTTGATTTGATGGGAAAATATCTTGAATCTGCGGCGAGGTTGGAAGAGCTATCGCGGATTGTGTCATCTGCTGCGAAGCCCAATAGGTCAAAGGGAACGCTACC</p>
  </blockquote>
  <p>As you can see, there is information about the start &quot;<code>start=2</code>&quot; and end &quot;<code>end=12</code>&quot; of a sequence within the header. I would like to slice the sequence like [start:end] and keep the rest of it. e.g</p>
  <p>The part I would like to trim:</p>
  <blockquote>
  <p>Ctttggtttcctttt</p>
  </blockquote>
  <p>And after trimming, I would like to keep the rest of the read:</p>
  <blockquote>
  <p>GTGTGTGAGGTTTGATTTGATGGGAAAATATCTTGAATCTGCGGCGAGGTTGGAAGAGCTATCGCGGATTGTGTCATCTGCTGCGAAGCCCAATAGGTCAAAGGGAACGCTACC</p>
  </blockquote>
  <p>So the new FASTA file will have reads like this:</p>
  <blockquote>
  <p>&gt;SRR5655563.745 745 length=126 (type=T,start=2,end=12,length=11,identity=81.8182%)
  GTGTGTGAGGTTTGATTTGATGGGAAAATATCTTGAATCTGCGGCGAGGTTGGAAGAGCTATCGCGGATTGTGTCATCTGCTGCGAAGCCCAATAGGTCAAAGGGAACGCTACC</p>
  </blockquote>
  <p>I have written a python script that takes a FASTA file as an input and outputs a trimmed FASTA file, like this:</p>
  <pre><code>tailtrim.py --fasta input.fasta --output output.tail.trimmed.fasta
  </code></pre>
  <p>The code does trim the reads where I want it to.</p>
  <pre><code>import numpy as np
  import argparse
  import re
  
  def main():
      parser = argparse.ArgumentParser()
  
      parser.add_argument(&quot;--fasta&quot;, type=str, required=True, help=&quot;input fasta file&quot;)
      parser.add_argument(&quot;--output&quot;, type=str, required=True, help=&quot;output tail.trimmed.fasta file&quot;)
  
      args = parser.parse_args()
  
      out_fasta = open(args.tail.trimmed.fasta, 'w')
  
      for line in open(args.fasta):
          header = line.rstrip()
          read = next(args.fasta).rstrip()
  
      #Extract header into a list
          header_lst = []
          header_lst= header.split(&quot; &quot;)
      
          tmp_start_lst = []
          tmp_end_lst = []
          tmp_lst = []
  
          for i in header_lst:
              if i.startswith(&quot;(&quot;) and i.endswith(&quot;)&quot;):
                  tmp_lst.append(i.split(&quot;,&quot;))
          #print(tmp_lst)
  
      # Extract the start and end numbers in a list
          for i in tmp_lst:
              for str in i: 
                  if str.startswith(&quot;start=&quot;):
                      tmp_start_lst.append(str)
                  if str.startswith(&quot;end=&quot;):
                      tmp_end_lst.append(str)
  
          pattern = re.compile(r'\d+$')
  
          start_lst = []
          for str in tmp_start_lst:
              match = re.search(pattern, str)
              start_lst.append(int(match.group()))
  
          end_lst = []
          for str in tmp_end_lst:
              match = re.search(pattern, str)
              end_lst.append(int(match.group()))
  
          #Extract reads into a list to manipulate i.e. trim
          read_lst = []
          read_lst.append(read)
  
          new_lst = []
          
          for str in read_lst:
              for num_start in start_lst:
                  for num_end in end_lst:
                      s = str.replace(str[(num_start-1):num_end],&quot;&quot;)
                      new_lst.append(s)
          
  </code></pre>
  <p>I do get the trimmed reads, but what I'm having trouble figuring out is how to write these trimmed reads with their corresponding headers to a new FASTA file.</p>
  <p>Also if there is any way that I could improve my code or employ better strategy to approach the problem, I would love to know.</p>
  <p>Best wishes.</p>
  <p>Edit: I tried running the solution by the super helpful user @Steve.</p>
  <p>The command I ran:</p>
  <pre><code>python3 tailTrimming.py --fasta tailtrim.fasta --output testtrim.trim.fasta
  </code></pre>
  <p>The command line error:</p>
  <pre><code>Traceback (most recent call last):
    File &quot;/home/x/Desktop/fastq/tailTrimming.py&quot;, line 61, in &lt;module&gt;
      main()
    File &quot;/home/x/Desktop/fastq/tailTrimming.py&quot;, line 58, in main
      SeqIO.write(trim_reads(fasta), out, &quot;fasta&quot;)
    File &quot;/home/x/.local/lib/python3.10/site-packages/Bio/SeqIO/__init__.py&quot;, line 478, in write
      count = writer_class(fp).write_file(sequences)
    File &quot;/home/x/.local/lib/python3.10/site-packages/Bio/SeqIO/Interfaces.py&quot;, line 209, in write_file
      count = self.write_records(records)
    File &quot;/home/x/.local/lib/python3.10/site-packages/Bio/SeqIO/Interfaces.py&quot;, line 193, in write_records
      for record in records:
    File &quot;/home/x/Desktop/fastq/tailTrimming.py&quot;, line 20, in trim_reads
      result = match.groupdict()
  AttributeError: 'NoneType' object has no attribute 'groupdict'
  </code></pre>
  <p>This is the whole input file I supplied:</p>
  <pre><code>&gt;SRR5655563.9676 9676 length=126 (type=T,start=1,end=11,length=11,identity=81.8182%)
  tttctttctttAGTTCCAATAGTCTTGACCACCTTTTATCAACAGAAGCTTGGCCTTGTCCAGTTATATATTGTATTGTACCCTCAGATTTCTCGCACAAT
  &gt;SRR5655563.10087 10087 length=126 (type=T,start=2,end=16,length=15,identity=80%)
  GtttgtttcattttttCCAAGGAAGAAATTCGACCTTCCAGCGATTTGTGGAGGTCATTCATCTGTTGAGTAAAGGATTGGTGCGCGACCTTGTAATCCTTGTGGAGGGTGTAG
  &gt;SRR5655563.13902 13902 length=126 (type=T,start=2,end=16,length=15,identity=80%)
  CtttttcttcttgtttGATGTAAAAAATCTTCGGTATCTAAAACGTATGAAACCTTAGATGAACTGCAAGCTATCTTACACTCTAGACCATTGATAATTT
  &gt;SRR5655563.18489 18489 length=126 (type=T,start=2,end=12,length=11,identity=81.8182%)
  CtttttcttcttCTTGGAAGTTTTGGATTCTGCAGGGACATTTTCTTTCTTTTCTCCATCTCCATCAGTCTCAACACCTGTCTTATCCTGAGCACCTTGAGACTCATCTTGACCATCTTTACTTT
  &gt;SRR5655563.20782 20782 length=126 (type=T,start=2,end=15,length=14,identity=71.4286%)
  CttcattttagttttCAACTCCTCTACCAACTGGGATGGTGCATTCAACTGTAGAACTGTTTCACGAATCTCCTTGAGAACACTGAAGTCTCCCTCAGTTAACTTCTTTTTCAAATTATTGA
  &gt;SRR5655563.23972 23972 length=126 (type=T,start=2,end=29,length=28,identity=75%)
  CttttttgttgttctcttctttcttctttGCATGGCTTGATGATGACTGATCCGATTGATTATTTCTTGATAGAATATCAATGTCATCACCAATTGTTGAGT
  &gt;SRR5655563.31739 31739 length=126 (type=T,start=1,end=10,length=10,identity=80%)
  ttttcttcttCTTGCATGAAAGTGGGTTTGGACCCTTAGCTCTTTTTCTCTTGAACTGAGGTTT
  &gt;SRR5655563.34244 34244 length=126 (type=T,start=2,end=14,length=13,identity=76.9231%)
  CtttcctttattttCTTGGAGGTTAGCCAGGATATTGGGATCAAAGCATGTAGCAAAACACACCTTGCTATTTCTTGCTCGTACAGATACATGGGATAGGA
  &gt;SRR5655563.38334 38334 length=126 (type=T,start=2,end=12,length=11,identity=81.8182%)
  CtttattgttttCTCATCACCCATATTATATTTCTTAAGGGCAGATTCCAACTCTTCCATTGTGATGTACCCGCTCTTATCATTGTCAAAATATTCAAAGGCTTTATATAGGCGATCCTCTCTTTC
  </code></pre>
  <p>And this is the whole output I have gotten:</p>
  <pre><code>&gt;SRR5655563.9676 9676 length=126 (type=T,start=1,end=11,length=11,identity=81.8182%)
  AGTTCCAATAGTCTTGACCACCTTTTATCAACAGAAGCTTGGCCTTGTCCAGTTATATAT
  TGTATTGTACCCTCAGATTTCTCGCACAAT
  </code></pre>
  <p>Just one read, that's all. Whereas I would like to keep all the sequences because all of them have this <code>start</code>, <code>end</code> attribute. The sequence being on two lines in the output is not something I did. It is like this in the output file. So it's no longer FASTA file, right?</p>
  <p>Thanks in advance for any help!</p>
   10775: <p>Here's one way using <a href="https://biopython.org/" rel="nofollow noreferrer">Biopython</a> and the <a href="https://biopython.org/wiki/SeqIO" rel="nofollow noreferrer">SeqIO</a> interface to read and write <a href="https://biopython.org/wiki/SeqRecord" rel="nofollow noreferrer">SeqRecord</a> objects. Using a generator, we can produce (yield) trimmed sequence records that can then be written to the output handle. This avoids storing an entire list of trimmed sequences in memory and is usually the way to go, assuming you're dealing with large files containing thousands of records:</p>
  <pre><code>import argparse
  import re
  
  from Bio import SeqIO
  </code></pre>
  <pre><code>def trim_reads(fileobj):
  
      pattern = (
          r'type=(?P&lt;type&gt;\w+),'
          r'start=(?P&lt;start&gt;\d+),'
          r'end=(?P&lt;end&gt;\d+),'
          r'length=(?P&lt;length&gt;\d+),'
          r'identity=(?P&lt;identity&gt;\d+(?:\.\d+)?)%'
      )
  
      for seq_record in SeqIO.parse(fileobj, &quot;fasta&quot;):
          match = re.search(pattern, seq_record.description)
          result = match.groupdict()
  
          start = int(result['start']) - 1
          end = int(result['end'])
  
          head = seq_record.seq[:start]
          tail = seq_record.seq[end:]
  
          seq_record.seq = head + tail
  
          yield seq_record
  </code></pre>
  <pre><code>def get_argument_parser():
  
      parser = argparse.ArgumentParser()
  
      parser.add_argument(
          &quot;--fasta&quot;,
           type=str,
           required=True,
           help=&quot;input fasta file&quot;,
      )
      parser.add_argument(
          &quot;--output&quot;,
          type=str,
          required=True,
          help=&quot;output tail.trimmed.fasta file&quot;,
      )
  
      return parser
  </code></pre>
  <pre><code>def main():
  
      parser = get_argument_parser()
      args = parser.parse_args()
  
      with open(args.fasta) as fasta, open(args.output, &quot;w&quot;) as out:
          SeqIO.write(trim_reads(fasta), out, &quot;fasta-2line&quot;)
  </code></pre>
  <pre><code>if __name__ == &quot;__main__&quot;:
      main()
  </code></pre>
  