#![allow(unused_imports)]

use std::cmp;
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
use std::fmt::{Debug, Display};
use std::io::{self, Read};
use std::str::{self, FromStr};


fn solve(h: usize, w: usize, s: Vec<String>) -> String {
    fn search_around(s: &[Vec<u8>], i: usize, j: usize, h: usize, w: usize) -> u8 {
        fn f(c: u8) -> u8 {
            (c == '#' as u8) as u8
        }

        let mut r = 0;
        if i > 0 && j > 0 {
            r += f(s[i - 1][j - 1]);
        }
        if i > 0 {
            r += f(s[i - 1][j]);
        }
        if i > 0 && j < w - 1 {
            r += f(s[i - 1][j + 1]);
        }
        if j > 0 {
            r += f(s[i][j - 1]);
        }
        if j < w - 1 {
            r += f(s[i][j + 1]);
        }
        if i < h - 1 && j > 0 {
            r += f(s[i + 1][j - 1]);
        }
        if i < h - 1 {
            r += f(s[i + 1][j]);
        }
        if i < h - 1 && j < w - 1 {
            r += f(s[i + 1][j + 1]);
        }
        r
    }

    let s = s.into_iter().map(String::into_bytes).collect::<Vec<_>>();
    let mut ls = Vec::new();
    for i in 0..h {
        let mut l = Vec::new();
        for j in 0..w {
            l.push(if s[i][j] == '.' as u8 {
                '0' as u8 + search_around(&s, i, j, h, w)
            } else {
                '#' as u8
            });
        }
        ls.push(l);
    }
    ls.into_iter()
        .map(|l| String::from_utf8(l).unwrap())
        .collect::<Vec<_>>()
        .join("\n")
}


fn main() {
    use std::io::Write;
    let stdin = io::stdin();
    let mut sc = Scanner::new(stdin.lock().bytes());
    let (h, w) = (sc.next(), sc.next());
    println!("{}", solve(h, w, sc.vec(h)));
}


struct Scanner<R: Read> {
    buf: Vec<u8>,
    bytes: io::Bytes<R>,
}

#[allow(dead_code)]
impl<R: Read> Scanner<R> {
    fn new(bytes: io::Bytes<R>) -> Self {
        Scanner {
            buf: Vec::with_capacity(256),
            bytes: bytes,
        }
    }

    fn next<T: FromStr>(&mut self) -> T
    where
        <T as FromStr>::Err: Debug,
    {
        self.buf.clear();
        for c in self.bytes
            .by_ref()
            .map(|c| c.unwrap())
            .skip_while(|&c| c == ' ' as u8 || c == '\n' as u8)
            .take_while(|&c| !(c == ' ' as u8 || c == '\n' as u8))
        {
            self.buf.push(c);
        }
        str::from_utf8(&self.buf).unwrap().parse().unwrap()
    }

    fn vec<T: FromStr>(&mut self, n: usize) -> Vec<T>
    where
        <T as FromStr>::Err: Debug,
    {
        (0..n).map(|_| self.next()).collect()
    }

    fn pairs<A: FromStr, B: FromStr>(&mut self, n: usize) -> Vec<(A, B)>
    where
        <A as FromStr>::Err: Debug,
        <B as FromStr>::Err: Debug,
    {
        (0..n).map(|_| (self.next(), self.next())).collect()
    }

    fn trios<A: FromStr, B: FromStr, C: FromStr>(&mut self, n: usize) -> Vec<(A, B, C)>
    where
        <A as FromStr>::Err: Debug,
        <B as FromStr>::Err: Debug,
        <C as FromStr>::Err: Debug,
    {
        (0..n)
            .map(|_| (self.next(), self.next(), self.next()))
            .collect()
    }

    fn mat<T: FromStr>(&mut self, m: usize, n: usize) -> Vec<Vec<T>>
    where
        <T as FromStr>::Err: Debug,
    {
        (0..n).map(|_| self.vec(m)).collect()
    }
}


#[allow(dead_code)]
fn print_yesno(x: bool, yes: &'static str, no: &'static str) {
    println!("{}", if x { yes } else { no });
}


#[allow(dead_code)]
fn print_foreach<T: Display, I: IntoIterator<Item = T>>(xs: I) {
    for x in xs.into_iter() {
        println!("{}", x);
    }
}


#[allow(dead_code)]
fn print_or<T: Display>(x: Option<T>, or: &'static str) {
    if let Some(x) = x {
        println!("{}", x);
    } else {
        println!("{}", or);
    }
}


Measured memory_bytes: 4352